Blotato
Create, schedule, and publish social media posts to 9 platforms from Claude, Cursor, or any AI agent. Hosted server with OAuth or API key auth.
Documentation
For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending
.mdto page URLs; this page is available as Markdown.
API reference for agents
This single-document reference includes client setup, authentication, all MCP tool names and input fields, REST operations and examples, platform requirements, and completion rules. Read the sections below without following links to learn the API and MCP workflows. Links to tutorials and template-specific examples are supplementary. Retrieve each template's current inputs before generating a visual.
Connection and verification
- For MCP, configure Streamable HTTP at
https://mcp.blotato.com/mcpwith OAuth or theblotato-api-keyheader supported by your client. - For REST, use
https://backend.blotato.com/v2with theblotato-api-keyheader. Keep keys out of chat messages, documentation, and shared configuration. - Verify MCP with
blotato_list_accounts, or REST withGET /v2/users/me/accounts. An empty account list is a successful authenticated result. - Select social accounts from returned IDs. Connect accounts through Accounts before publishing.
Reading this document does not install a server or authorize an account. An installed plugin with no connected account or no tools has not passed verification. OAuth authorization and a successful tool call are separate checks.
Execution rules
- Use only tools exposed by the connected client. REST and MCP do not expose identical operations or argument shapes.
- Read the selected tool's schema. Get account, Page, board, playlist, post, schedule, and template IDs from responses rather than inventing them.
- Get the user's approval for the intended write operation. Do not publish, send messages, activate automations, delete content, or purchase credits as a connection test.
- Pass public media URLs directly. For a local file, request upload URLs, PUT the bytes, verify upload success, then use the returned public URL.
- Save returned IDs. Follow each operation's completion states below. A submitted or scheduled request is not proof of publication.
- After an uncertain write response, check existing work before retrying. A repeated create request risks duplicate content.
- Report the returned status, error, scheduled time, or published URL. Do not claim unsupported features or unverified client compatibility.
Contents
- Use Blotato with an AI agent
- Search and read the help docs
- Connect your AI client
- API access and authentication
- REST API versus MCP
- MCP input index
- Tools Reference
- Accounts and identifiers
- Async jobs and polling
- Media uploads and conversion
- Post lifecycle
- Scheduling posts
- API rate limits
- Errors and retries
- Diagnose and answer a support question
- Find a post's outcome before retrying
- Publish and verify a post
- Schedule and manage posts
- Upload local media
- Create and publish a visual
- Extract and repurpose content
- Read post analytics
- Read and reply to comments
- Read and reply to messages
- Manage DM automations
- Check or add credits
- REST API quickstart
- Public API operation index
- Users
- Accounts
- Credits /v2/credits
- Upload Media /v2/media
- Publish Post /v2/posts
- Get Post /v2/posts/:postSubmissionId
- List Posts /v2/posts
- List Published Posts /v2/published-posts
- Analytics /v2/analytics
- Analytics Metrics Reference
- Comments /v2/comments
- Messages /v2/messages
- DM Automations /v2/dm-automations
- Create Source /v2/source-resolutions-v3
- Get Source /v2/source-resolutions-v3/:id
- Visual Templates
- Create Visual /v2/videos/from-templates
- Get Visual Status /v2/videos/creations/:id
- Delete Video /v2/videos/:id
- Scheduled Posts /v2/schedules
- Schedule Slots
- Instagram: API and MCP publishing
- Facebook: API and MCP publishing
- TikTok: API and MCP publishing
- YouTube: API and MCP publishing
- LinkedIn: API and MCP publishing
- Pinterest: API and MCP publishing
- X (Twitter): API and MCP publishing
- Threads: API and MCP publishing
- Bluesky: API and MCP publishing
- Async Workflows
Use Blotato with an AI agent
This is the entry point for customer assistants executing tasks and support agents answering questions. Website instructions describe actions an agent performs or explains to the customer. They are not interchangeable with REST or MCP calls.
Route the request
Use context already supplied. Ask only for a missing fact which changes the next action.
- Identify the requested outcome and whether you are executing it or explaining it.
- Identify the surface: Blotato website, MCP, REST, n8n, or Make.
- Identify the client, destination platform, and failing stage when relevant.
- Identify the artifact: workflow JSON, local media file, hosted media URL, generated visual, draft, scheduled item, or published post.
- Check which provider owns the endpoint, key, or node. A Blotato key does not authenticate another provider.
For support, follow Diagnose and answer. Answer the customer's question before offering a tutorial. Preserve completed checks and human corrections.
Website Modes and Current Navigation
Developer Platform is the website navigation for monitoring API, MCP, and automation work. Content Studio is the navigation for the in-app AI Agent and visual creation. Switching modes does not change the subscription, accounts, or content, and does not connect an external assistant.
- In-app AI Agent: Content Studio > Post editor. New draft inside the workspace creates a blank draft, not AI output.
- Connect or reconnect social destinations: Accounts > Connect account, or the existing account's actions menu > Reconnect. Accounts is no longer a Settings tab.
- Publication results: Posts > Scheduled, Published, or Failed. Select the platform and time window before concluding a post is missing.
- Recurring slots: Calendar > Weekly schedule, within the Weekly posting schedule section.
- Performance rankings: Analytics > Top posts, not the old Published > Top Performing tab.
- API activity and errors: Developer Platform > Logs.
- Instagram and Facebook comments and messages: Inbox > Posts or Chats.
- Inspiration, Prompts, and Viral AI Coach: Tools.
- Credentials and client setup: Settings > API. Language and reset controls: Settings > Profile. Credits and subscription: Settings > Billing.
Use Website modes and navigation for the screen-by-screen map and screenshots. The draft's Photo / Video control uploads existing media. Do not send users there to find the old image-generation menu.
Connect and verify
- Select the exact client in MCP setup, or use the REST quickstart for HTTP, n8n, or Make.
- Confirm paid access. Generating an API key during a trial starts billing. Read authentication before generating a key.
- Call
blotato_list_accounts, orGET /v2/users/me/accounts. - Select the requested social destination from the response. Connect missing accounts in Accounts.
An empty list proves authentication, not publishing readiness. A saved connector, OAuth redirect, or “Connected” label alone does not prove a tool call works. ChatGPT.com and Codex have separate setup paths.
Choose a task
| Outcome | Execute through API or MCP | Explain website actions |
|---|---|---|
| Connect a social destination | IDs and destinations | Social account settings |
| Publish or cross-post | Publish and verify | Create posts |
| Schedule, reschedule, or cancel | Manage schedules | Calendar |
| Upload or use existing media | Upload and prepare media | Attach media |
| Generate images, carousels, or video | Generate and verify | Video templates |
| Extract or repurpose source content | Extract a source | Context |
| Inspect performance | Analytics | Checkpoints and pending data |
| Read or reply to Instagram and Facebook comments | Comments | Inbox |
| Read or reply to Instagram and Facebook direct messages | Messages | Inbox |
| Set up keyword-triggered replies | DM automations | DM automation guide |
| Check balance or purchase credits | Credits | Billing and credits |
| Diagnose a failure | Errors and retries | Support diagnosis |
Instructions for the agent
- Use only available tools and the selected operation's schema. REST and MCP differ in fields and operation coverage.
- Retrieve current IDs. After reconnection, re-list accounts. Never substitute a social-platform post ID, submission ID, or schedule ID for another ID type.
- Check platform requirements and media requirements before a write.
- Confirm the requested destination and authorization. Connection tests must not publish, send messages, purchase credits, or activate automations.
- Record returned IDs. Use operation-specific completion rules, including error fields inside successful HTTP or MCP responses.
- Inspect existing work after an uncertain write. Do not blindly repeat a create request.
- Report the verified status, scheduled time, or returned media/public URL. Explain what remains unresolved.
Documentation for retrieval
Start with the task page, then retrieve only the contract or diagnosis needed.
| Resource | Use |
|---|---|
| Search and read help | Optional public documentation MCP lookup, separate from account access |
| MCP tools | Available tools and behavior |
| MCP input index | Required and optional tool arguments |
| API reference for agents | Generated setup, contracts, examples, and completion rules in 1 document |
| Documentation index | Find a page outside this task index |
| Full documentation text | Whole-corpus retrieval when required |
| OpenAPI JSON | Published REST schemas |
Reading documentation does not install a server, authorize an account, or execute a task.
Search and read the help docs
Use the task index when the outcome is known. For another question, search published help pages through the documentation MCP server. This is an optional lookup route, not another requirement for publishing.
Choose the server
| Purpose | Server | Access |
|---|---|---|
| Look up published help | Documentation MCP endpoint | Public documentation. No Blotato API key or account authorization required. |
| Work with connected social accounts | https://mcp.blotato.com/mcp | Follow client setup and verify account access. |
The documentation server does not connect social accounts or publish posts. Its results describe published documentation, not unpublished repository edits.
Find the answer
- Add the documentation endpoint to an HTTP MCP client under a distinct name such as
blotato-docs, if a docs connection is needed. - Discover its tools with
tools/list. - Call
searchDocumentationwith aquerystring. - Select a result for the customer's surface: API/MCP execution or Blotato website instructions.
- Call
getPagewith the result's page URL inurl. - Read the page before answering or constructing a request.
| Tool | Input | Use |
|---|---|---|
searchDocumentation | query | Retrieve matching help-page excerpts and URLs. |
getPage | url | Retrieve the selected page's Markdown. |
Example search input:
{"query":"schedule timezone"}
A search result about a website button is not an API parameter reference. A result about API scheduling is not a website walkthrough. Search rank alone does not establish relevance or correctness. Follow the task index when results mix surfaces.
Keep API keys and customer data out of documentation queries. Use search and page retrieval for lookup. The server also advertises askQuestion and sendFeedback. Feedback sends a report, so require the user's request before using it.
Without a docs MCP connection
- Read the task index or documentation index.
- Fetch the selected page as Markdown by appending
.mdto its published URL.
For account actions, return to Blotato client setup. Reading help documentation does not verify access to a customer's connected accounts.
The hosted documentation endpoint is provided by GitBook. See GitBook's published-docs MCP requirements.
Connect your AI client
Choose your client below. Blotato's MCP server runs remotely at https://mcp.blotato.com/mcp using Streamable HTTP.
Before you start
- Confirm your paid Blotato subscription. API and MCP access is not included in the free trial.
- Connect social accounts in Accounts.
- For an API-key setup, copy the full key from Settings > API. Generating a key during a trial ends the trial and starts billing.
An account connection is needed for publishing. You still receive a successful empty account list before connecting social accounts.
Choose your client
Open Settings > API for the client chooser. Select the app you use, not another app with a similar chat interface. ChatGPT.com and ChatGPT desktop (Codex) have separate setup instructions. A Blotato subscription is separate from your AI client's subscription.
For step-by-step setup with a test post, open the API setup wizard instead.
After setup, ask your client to list connected Blotato accounts. A Connected badge alone does not verify a tool call. A successful empty list means the connection works but no social accounts are connected.
Claude.ai
- Open Claude connectors.
- Add a custom connector named
Blotato. - Enter
https://mcp.blotato.com/mcpas the URL. - Connect and approve access in the browser.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
Log into the intended Blotato account in the browser during authorization. If access fails, follow OAuth troubleshooting.
Claude Desktop / Cowork
- Open Customize, then Connectors.
- Add a custom connector named
Blotato. - Enter
https://mcp.blotato.com/mcpas the URL. - Connect and approve access in your browser.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
On a managed workspace, ask the workspace admin if adding connectors is restricted. If authorization repeatedly fails after reconnecting, follow the stale-session steps.
For local media, the assistant also needs file access and permission to reach the upload destination. Follow upload troubleshooting.
Video: Claude Cowork and Desktop setup.
Claude Code
- Run this command in your terminal:
claude mcp add --transport http blotato https://mcp.blotato.com/mcp
- Open Claude Code.
- Run
/mcp. - Select Blotato and authenticate through the browser.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
For an API-key setup instead of OAuth, use this command when adding the server. Replace the placeholder with your full API key:
claude mcp add --transport http blotato https://mcp.blotato.com/mcp --header "blotato-api-key: YOUR_API_KEY"
If Blotato is already configured, manage that entry through /mcp before adding it again. Keep API keys out of shared project configuration.
See Claude Code's MCP documentation and Blotato's Claude Code tutorials.
ChatGPT desktop (Codex)
- In the ChatGPT desktop app, open Plugins, then MCPs.
- Click Add, then Add MCP server.
- Name it
blotato. - Select Streamable HTTP. The form opens on STDIO.
- Enter
https://mcp.blotato.com/mcpas the URL. - Under Headers, set
blotato-api-keyto your full API key. - Leave Bearer token env var blank when using the header above.
- Save and restart the MCP connection or client.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
For Codex CLI with OAuth:
codex mcp add blotato --url https://mcp.blotato.com/mcp
codex mcp login blotato
For an API key in Codex's ~/.codex/config.toml, use TOML:
[mcp_servers.blotato]
url = "https://mcp.blotato.com/mcp"
http_headers = { "blotato-api-key" = "YOUR_API_KEY" }
Replace the placeholder and keep the key in your personal configuration. The CLI also supports a bearer-token environment variable if your environment supplies it.
See OpenAI's MCP configuration guide.
ChatGPT.com / Work
Use OpenAI's custom MCP connection flow on ChatGPT.com:
- Open ChatGPT Plugins.
- Click Add in the top right corner, then Add custom MCP server.
- Enter the name
Blotato, a description, and server URLhttps://mcp.blotato.com/mcp. - Choose OAuth authentication.
- Select I understand and want to continue.
- Click Create as a plugin.
- Click Connect Blotato.
- On the Blotato page, sign in if asked, review the access request, and click Approve access.
- Start a new chat with Blotato selected in the tools menu.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
If the plugin exists but has no connected account, open Settings → Plugins → Blotato → Connect another account → Sign in with Blotato. Adding the plugin and authorizing an account are separate steps.
“No app tools available yet” means the setup has not passed verification. Check account authorization and tool discovery before retrying the prompt. If sign-in fails, record the error and follow authentication troubleshooting. Do not describe the connection as working until a tool call succeeds.
Custom MCP servers work on the ChatGPT Free plan. In a workspace, availability depends on the workspace policy. This creates a custom connection, rather than installing a Blotato listing from the public directory. For the desktop app or the Codex CLI, use the ChatGPT desktop (Codex) tab.
Cursor
- Open your personal
~/.cursor/mcp.jsonconfiguration. - Add the Blotato entry below, preserving any existing servers.
- Replace
YOUR_API_KEYwith your full key. - Save and restart Cursor.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
{
"mcpServers": {
"blotato": {
"url": "https://mcp.blotato.com/mcp",
"headers": {
"blotato-api-key": "YOUR_API_KEY"
}
}
}
}
Use Cursor's personal configuration for a literal API key. For variable substitution and workspace configuration, see Cursor's MCP documentation.
VS Code
For VS Code's MCP configuration:
- Open
.vscode/mcp.jsonin your workspace, preserving any existing servers. - Add the configuration below.
- Start the Blotato server from the editor's MCP controls.
- Enter your full Blotato API key when prompted.
- Ask the chat assistant: “List my connected Blotato accounts using
blotato_list_accounts.”
{
"inputs": [
{
"type": "promptString",
"id": "blotato-api-key",
"description": "Blotato API key",
"password": true
}
],
"servers": {
"blotato": {
"type": "http",
"url": "https://mcp.blotato.com/mcp",
"headers": {
"blotato-api-key": "${input:blotato-api-key}"
}
}
}
}
This uses VS Code's servers format, rather than Cursor's mcpServers format. Interactive input variables apply to the extension host. For VS Code Agent Host configuration and restrictions, follow the VS Code MCP reference.
Hermes
- Run
hermes config editto open your Hermes configuration, or open~/.hermes/config.yaml. - Add the Blotato entry below under
mcp_servers. - Replace
YOUR_API_KEYwith your full key. - Save and restart Hermes.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
mcp_servers:
blotato:
url: "https://mcp.blotato.com/mcp"
headers:
blotato-api-key: "YOUR_API_KEY"
If mcp_servers is already in the file, add only the blotato entry under it. A second mcp_servers key makes the file invalid, and Hermes keeps loading the previous configuration without Blotato. See Hermes' MCP documentation.
OpenClaw
- Replace
YOUR_API_KEYin the command below with your full key. - Run the command in your terminal.
- Ask: “List my connected Blotato accounts using
blotato_list_accounts.”
openclaw mcp add blotato --url https://mcp.blotato.com/mcp --transport streamable-http --header "blotato-api-key=YOUR_API_KEY"
Keep --transport streamable-http: without it, OpenClaw can't connect to Blotato. See OpenClaw's MCP documentation.
Other clients
For Antigravity, Replit Agent, or another remote-MCP client:
- Open the client's MCP configuration.
- Select Streamable HTTP.
- Set the URL to
https://mcp.blotato.com/mcp. - Complete OAuth if supported, or set a
blotato-api-keyheader to your full API key. - Reload the connection.
- Ask the assistant to call
blotato_list_accounts.
Some clients accept the JSON copied from Settings > API under Other MCP Clients. Check the client's configuration format before pasting it. Codex uses TOML, and VS Code uses a different JSON wrapper.
For a form with a Headers section, enter the full key as the value for blotato-api-key. Leave Bearer token env var blank when using this header.
Verify your connection
The verification call is blotato_list_accounts. It returns an array containing account IDs, platforms, names, and subaccounts. An empty array is a valid result when you have no connected accounts.
If no tool call runs, check whether the client enabled the connection. If the call returns an error, use the authentication guide and the troubleshooting steps below.
After verification, choose an agent workflow.
Tutorials
Upload your own local images or videos via MCP
The Blotato MCP tools (blotato_create_post, blotato_create_design) do not accept local file paths. Media must be a publicly accessible URL. Allowlisting egress to database.blotato.io is necessary but not enough on its own. You still upload the file first.
To use a local file:
- Call
blotato_create_presigned_upload_urlwith your filename (include the extension). It returns apresignedUrland apublicUrl. - Upload the raw file bytes to
presignedUrlwith an HTTPPUT(for examplecurl -X PUT "<presignedUrl>" --data-binary "@<local_file>"). Send raw bytes, not JSON and not multipart form data. - Pass the returned
publicUrlin themediaUrlsfield ofblotato_create_post.
Do not pass the local file directly to blotato_create_post. If you allowlisted database.blotato.io but the upload still fails, the file was likely sent directly instead of being PUT to the presigned URL, or the PUT used the wrong body encoding.
Troubleshooting
If the MCP server connects but does not work as expected:
- OAuth clients (Claude.ai, Desktop, Cowork, Claude Code): Make sure you are logged into your Blotato account in the browser. The OAuth approval requires an active Blotato session.
- API-key connections (for example, Cursor or a Codex header configuration): Double check you copy/pasted the correct API key from Settings > API. Make sure there are no extra spaces or missing characters. If your key ends with one or more
=characters, copy the full key including the trailing=, since dropping it causes a 401 "invalid API key" error. - Reload or restart the client after saving its MCP configuration.
- OAuth authorization fails: Check the client-specific tab. If the client supports API-key headers, use that tab’s API-key configuration. Codex uses TOML and header form fields. Cursor uses JSON. Do not paste one client’s configuration into another client.
- Give your assistant the agent reference and ask it to call
blotato_list_accounts. Reading documentation does not install the MCP server, authorize an account, or expose tools to a chat. - If the connector shows "Connected" but a tool fails, inspect the returned error. A subscription-related
403requires an active paid plan. A401points to credentials or session authentication. Follow authentication checks. Generating an API key during a trial starts the paid subscription. - An empty account list is a successful call. Connect a social account in Accounts before publishing.
- For a JSON parsing error, use your editor's local JSON validation. Check for missing commas and unmatched braces. Do not paste configuration containing an API key into an online validator.
- Connector shows "Connected" but never authenticates (stale connector session). If the Blotato connector in Claude Cowork or Claude Desktop shows Connected but every tool call fails with a credential error, and reconnecting does not help, the client is reusing a stale cached session. A simple reconnect reuses that same cached session, so remove it fully and add it fresh:
- Go to Customize > Connectors and fully remove the Blotato connector
- Click the + button, choose Add custom connector, and approve access again
- To double-check the key itself, see Settings > API
- "Access to this website is blocked by your network egress settings" during a presigned upload. Claude Cowork and Claude Desktop block outbound network access by default, so the
PUTto the presigned upload URL cannot reachdatabase.blotato.io. To allow it:- Go to Claude Cowork/Desktop > Settings > Capabilities > Allow network egress
- Set "Package managers only"
- Under Additional allowed domains, add
database.blotato.ioand click Add - Fully quit and restart Claude Cowork/Desktop
- If your settings look correct but the upload stays blocked, set Allow network egress to "Allow all" instead of "Package managers only", then restart and retry
Video walkthroughs: Claude + Blotato Beginner Setup and Build Your AI Personal Assistant for Social Media Marketing
API access and authentication
API and MCP access is included in paid Starter, Creator, and Agency subscriptions. The free trial does not include API or MCP access. Generating an API key during a trial ends the trial and starts the paid subscription.
REST API
- Open Settings > API.
- Generate or copy your API key.
- Include the key in the
blotato-api-keyheader of each request. - Call
GET https://backend.blotato.com/v2/users/me/accountsto verify access.
GET /v2/users/me/accounts HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Copy the full key, including any trailing = characters. Preserve the value exactly. JSON values use double quotes. Store credentials in your client's secret settings or environment, outside published examples.
MCP
The server uses Streamable HTTP at https://mcp.blotato.com/mcp and accepts these authentication methods:
| Method | Configuration |
|---|---|
| OAuth | Add the server URL and complete the browser authorization flow |
| API key header | Set blotato-api-key to your API key |
| Bearer header | Set Authorization to Bearer YOUR_API_KEY |
Use the configuration supported by your client in the setup guide. A field named “Bearer token env var” expects an environment variable name, rather than the key itself. For a header-value form, paste the key into the header value.
After connecting, ask the assistant to call blotato_list_accounts. An empty array is a successful authenticated response with no connected accounts.
Resolve access errors
| Result | Next action |
|---|---|
401 or invalid credentials | Recopy the full API key, or repeat OAuth authorization in the client |
403 with a subscription message | Check the subscription in Billing |
| OAuth fails but an API-key request succeeds | Follow the OAuth session troubleshooting steps for the client |
| Accounts are missing | Confirm the Blotato account used to authorize, then check Social accounts |
Use the returned error to choose the next step. An OAuth error alone does not establish a billing problem.
REST API versus MCP
Both interfaces use your Blotato account and subscription. Choose the interface your assistant or automation uses.
| MCP | REST API | |
|---|---|---|
| Use from | An assistant with MCP tools | HTTP code, n8n, Make, or other workflow tools |
| Connect to | https://mcp.blotato.com/mcp | https://backend.blotato.com/v2 |
| Authenticate | OAuth or an API key, depending on the client | blotato-api-key header |
| Publish input | Tool arguments such as accountId, platform, text, and mediaUrls | A JSON body containing post.accountId, post.content, and post.target |
| Account lookup | blotato_list_accounts includes subaccounts | Fetch accounts, then fetch subaccounts when needed |
| Immediate post and source completion | Tools wait internally for up to 20 seconds, then return the available result | Submit, save the returned ID, and poll the status endpoint |
| Visual completion | Call blotato_get_design_status | Poll the visual status endpoint |
| Reference | MCP tools | OpenAPI |
MCP tools expose a selected set of workflows. An endpoint in OpenAPI does not imply a corresponding MCP tool. For example, REST includes schedule-slot management and a webhook publishing target. MCP manages scheduled posts and publishes to the 9 listed social platforms, but does not expose these 2 REST capabilities.
Choose your setup
- If your assistant already has
blotato_tools, call those tools directly using their schemas. - If you are adding Blotato to an assistant, follow MCP setup.
- If you are building HTTP requests, follow the REST quickstart.
- If you use workflow software, follow the n8n or Make guide.
Keep the 2 request shapes separate. Copying a REST post object into an MCP tool call fails when the tool expects flat arguments.
MCP input index
This field index covers the 35 tools listed by Blotato's MCP server. Use the connected tool schema for types, nested objects, allowed values, and defaults.
Required below means required by the tool-level input schema. Platform-specific conditions still apply. For example, Facebook needs a page ID and TikTok needs its privacy and disclosure fields. Follow the platform guides.
These are MCP arguments, not REST bodies. Read REST versus MCP before translating a request.
| Tool | Required arguments | Optional arguments |
|---|---|---|
blotato_get_user | — | — |
blotato_list_accounts | — | platform |
blotato_list_pinterest_boards | accountId | — |
blotato_create_automation | accountId, platform, name, dmMessage | pageId, triggers, buttons, followGate, emailGate, webhook, commentReply, isActive |
blotato_list_automations | — | limit, cursor |
blotato_list_automation_runs | automationId | limit, cursor, status, since |
blotato_list_automation_logs | automationId | flowRunId, limit, cursor |
blotato_get_automation_analytics | automationId | — |
blotato_update_automation | automationId | name, triggers, dmMessage, buttons, followGate, emailGate, webhook, commentReply, isActive |
blotato_update_automation_trigger | automationId, triggerId, isActive | — |
blotato_delete_automation | automationId | — |
blotato_list_comments | — | limit, cursor, platform, accountId, postId, parentCommentId, since, until |
blotato_get_comment | commentId | — |
blotato_post_comment | postId, text | parentCommentId |
blotato_get_credits | — | — |
blotato_create_presigned_upload_url | filename | — |
blotato_list_conversations | — | limit, cursor, platform, accountId |
blotato_get_conversation | conversationId | — |
blotato_list_messages | — | conversationId, limit, cursor, platform, accountId |
blotato_get_message | messageId | — |
blotato_send_message | accountId, platform, recipientId, text | pageId, commentId, buttons, quickReplies |
blotato_create_post | accountId, platform, text | mediaUrls, additionalPosts, pageId, mediaType, link, replyControl, privacyLevel, disabledComments, disabledDuet, disabledStitch, isBrandedContent, isYourBrand, isAiGenerated, autoAddMusic, isDraft, imageCoverIndex, videoCoverTimestamp, boardId, title, altText, collaborators, coverImageUrl, shareToFeed, audioName, firstComment, trial, privacyStatus, shouldNotifySubscribers, isMadeForKids, containsSyntheticMedia, thumbnailUrl, playlistIds, scheduledTime, useNextFreeSlot |
blotato_get_post_status | postSubmissionId | — |
blotato_list_posts | — | since, until, limit, cursor, status, platform |
blotato_list_schedules | — | limit, cursor |
blotato_get_schedule | id | — |
blotato_update_schedule | id | scheduledTime, post |
blotato_delete_schedule | id | — |
blotato_create_source | sourceType | url, text, customInstructions |
blotato_get_source_status | id | — |
blotato_list_design_templates | — | search, id |
blotato_create_design | templateId | inputs, prompt, render, title |
blotato_get_design_status | id | — |
blotato_list_top_posts | — | since, until, platform, sortBy, limit |
blotato_get_post_analytics | id | — |
For results, workflow order, and recovery, use the tool reference and agent workflows.
Tools Reference
The Blotato MCP Server exposes 35 tools. Use the connected tool's input schema for its arguments. Start with client setup or choose an agent workflow.
Call blotato_list_accounts before publishing. Follow completion rules after submitting a post, visual, source, comment, or message. REST JSON bodies and MCP tool arguments have different shapes.
Accounts
For every tool's required and optional argument names, see the MCP input index. The sections below explain behavior and results.
blotato_get_user
Get your account info and verify the connection is working.
- Input: none
- Output: user ID, subscription status, and subscription plan
blotato_list_accounts
List all connected social media accounts with subaccounts (for Facebook Pages and LinkedIn Company Pages).
- Input:
platform(optional) - filter by platform name - Output: array of accounts with ID, platform, name, username, and subaccounts
blotato_list_pinterest_boards
List boards owned by a connected Pinterest account. Use this to get the boardId required when publishing a Pinterest pin.
- Input:
accountId(required) - Pinterest account ID from blotato_list_accounts - Output: array of boards with
idandname. UseidasboardIdin blotato_create_post.
Credits
blotato_get_credits
Get the account's remaining credits, the account email the API key belongs to, and current pricing (price per 1,000 credits and the min/max purchase quantity). If the user wants more credits, state the returned account email, then direct them to Settings > Billing. Credits are non-transferable between accounts.
- Output:
creditsRemaining,accountEmail,purchaseQuantityRange(minandmax), andpricePer1000CreditsUsd.
Publishing
blotato_create_post
Create and publish (or schedule) a post to a social media platform.
- Input:
accountId(required) - from blotato_list_accountsplatform(required) - twitter, instagram, facebook, tiktok, linkedin, pinterest, bluesky, threads, or youtubetext(required) - post contentmediaUrls(optional) - array of public media URLsscheduledTime(optional) - ISO 8601 datetimeuseNextFreeSlot(optional) - use next available schedule slotpageId(optional) - for Facebook/LinkedIn pagesmediaType(optional) - for Instagram/Facebook: reel or story. Facebook videos must be"reel"(regular feed videos no longer supported).trial(optional) - for Instagram reels: object withgraduationStrategy("MANUAL"or"SS_PERFORMANCE"). Trial reels are shown to non-followers first.firstComment(optional) - for Facebook/Instagram: text auto-posted as the first comment right after publishing. Not supported for stories. Useful for links.privacyLevel(optional) - for TikTokadditionalPosts(optional) - array of additional posts for threads (Twitter, Bluesky, Threads). Each entry hastextandmediaUrls. The first post uses the top-leveltextandmediaUrlsfields. Blotato handles reply chaining.boardId(optional) - for Pinterest (get from blotato_list_pinterest_boards)title(optional) - for Pinterest or YouTubeprivacyStatus(optional) - for YouTube: public, private, or unlistedplaylistIds(optional) - for YouTube: array of playlist IDs from blotato_list_accounts to add the video to playliststhumbnailUrl(optional) - for YouTube: publicly accessible image URL for a custom thumbnail. Requires a verified YouTube account in good standing
- Output: postSubmissionId (poll with blotato_get_post_status)
blotato_get_post_status
Check the status of a submitted post.
- Input:
postSubmissionId(required) - Output: status, publicUrl (when available on a published result), errorMessage (when failed)
- Status values: in-progress -> published | scheduled | failed
in-progress also covers a lookup with no matching result record. It does not validate a guessed ID or confirm a live queue job. Use the original submission ID, keep a polling limit, and follow post lifecycle.
blotato_list_posts
List the user's posts (scheduled, published, and failed) within a time window, ordered by post time (most recent first). Supports cursor-based pagination and optional filters by status and platform.
Each item includes an account field and a state field with a type of scheduled, published (includes postUrl and analytics), or failed (includes errorMessage). account is null when the connected account no longer exists. Published-post analytics are null until metrics have been collected.
- Input:
since(optional) - ISO 8601 timestamp. Defaults to 7 days ago.until(optional) - ISO 8601 timestamp. Defaults to 7 days from now.limit(optional) - number of posts per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous responsestatus(optional) - array of statuses to include:scheduled,published,failed. Omit to include all.platform(optional) - array of platforms to include: twitter, instagram, linkedin, facebook, tiktok, pinterest, threads, bluesky, youtube. Omit to include all.
- Output: array of posts with
id,postTime,platform,text,mediaUrls,account, and astateobject. A published state includesanalytics.latestandanalytics.history, oranalytics: null. Includescursorfor the next page when more pages are available.
Analytics
blotato_list_top_posts
List your top performing published posts, ranked by an engagement metric over a time range. Use this to answer questions like "what were my best posts last month" or "which posts got the most views".
Each item includes the post content, public URL, platform, publish time, media URLs, the latest analytics snapshot, and the full snapshot history. Analytics are refreshed periodically in the background, so recent posts may have no metrics yet. Metric values are returned as strings because counts can exceed normal number precision.
- Input:
since(optional) - ISO 8601 timestamp. Only include posts published on or after this time. Defaults to 30 days ago.until(optional) - ISO 8601 timestamp. Only include posts published on or before this time. Defaults to now.platform(optional) - the MCP tool acceptstwitter,instagram,facebook,threads, orblueskyas an explicit filter. Omit to include all available results. The REST analytics endpoint also accepts TikTok, YouTube, and Pinterest filters. The MCP filter list is narrower than the backend's collection coverage.sortBy(optional) - metric to rank by:likes_count,comments_count,views_count, orreach_count. Defaults toviews_count. For Twitter/X, comments ranking usesreplies_countwhen comments are not reported, and views ranking usesimpressions_countwhen views are not reported.limit(optional) - number of posts to return. Min: 1, Max: 100. Default: 20
- Output: array of
items, each withid,content,postUrl,platform,createdAt,mediaUrls,latestMetrics, andmetricsHistory.
blotato_get_post_analytics
Get analytics for a single published post, including the latest metrics and the full snapshot history. This does not trigger a re-fetch; it returns the most recent analytics collected in the background.
Use blotato_list_posts or blotato_list_top_posts to find the published post id first.
- Input:
id(required) - published post id from blotato_list_posts or blotato_list_top_posts - Output:
publishedPostId,platform,lastFetchedAt,lastError,metrics(latest, or null when not synced yet), andhistory(array of snapshots, each withfetchedAtandmetrics).
Comments
Read and post comments on your published Instagram and Facebook posts, both audience replies and comments you post through Blotato.
blotato_list_comments
List comments on your published posts, ordered by creation time (most recent first). Supports cursor-based pagination and optional filters.
Each comment includes an isAuthor flag: true for comments you posted, false for audience replies, and an author object with the commenter's username (Instagram) or name (Facebook), both null for comments you posted.
- Input:
limit(optional) - number of comments per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous responseplatform(optional) - filter by platform:instagramorfacebookaccountId(optional) - filter to a single connected accountparentCommentId(optional) - filter to direct replies to a single commentpostId(optional) - filter to comments on a single Blotato-published post (from blotato_list_posts)since(optional) - only include comments created on or after this ISO 8601 timestampuntil(optional) - only include comments created on or before this ISO 8601 timestamp
- Output: array of comments with
id,text,status,isAuthor,author,platform,postId,parentCommentId,createdAt, anderrorMessage(when failed). Includescursorfor the next page when present.
blotato_get_comment
Get a single comment by its Blotato ID.
- Input:
commentId(required) - comment ID from blotato_list_comments - Output:
id,text,status,isAuthor,author,platform,postId,createdAt, anderrorMessage(when failed)
blotato_post_comment
Post a comment on one of your published Instagram or Facebook posts, or a reply to an existing top-level comment when you pass parentCommentId. Blotato queues the comment and posts it in the background. To check the status of the comment, poll with blotato_get_comment. Replies to audience comments count toward your monthly active-contacts limit.
- Input:
postId(required) - Blotato ID of the published post (from blotato_list_posts)text(required) - comment body. Instagram allows up to 2200 characters, Facebook up to 8000parentCommentId(optional) - Blotato ID of a top-level, posted comment on the same post to reply to. Replies to replies are not supported
- Output: the queued comment (poll with blotato_get_comment)
- Status values: queued -> processing -> posted | failed
Messages
Read and send direct messages on your Instagram account and Facebook Page. Reply to people who already have a conversation with you.
blotato_list_conversations
List your direct-message conversations, ordered by most recent activity. Supports cursor-based pagination and optional filters.
- Input:
limit(optional) - number of conversations per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous responseplatform(optional) - filter by platform:instagramorfacebookaccountId(optional) - filter to a single connected account
- Output: array of conversations with
id,platform,participants,updatedAt, andcreatedAt. Includescursorfor the next page when present.
blotato_get_conversation
Get a single conversation by its Blotato ID.
- Input:
conversationId(required) - conversation ID from blotato_list_conversations - Output: conversation object with
id,platform,participants, andupdatedAt
blotato_list_messages
List your messages, ordered by creation time (most recent first). Supports cursor-based pagination and optional filters.
- Input:
limit(optional) - number of messages per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous responseconversationId(optional) - filter to a single conversationplatform(optional) - filter by platform:instagramorfacebookaccountId(optional) - filter to a single connected account
- Output: array of messages with
id,conversationId,direction,text,payload,status,senderId,recipientId, andcreatedAt.directionisincomingfor messages you receive andoutgoingfor messages you send. Includescursorfor the next page when present.
blotato_get_message
Get a single message by its Blotato ID. Poll this after blotato_send_message to check whether an outgoing message reached sent or failed.
- Input:
messageId(required) - message ID from blotato_list_messages - Output: message object with
id,conversationId,direction,text,payload,status,senderId,recipientId, andcreatedAt
blotato_send_message
Send a direct message to one recipient, or a private reply to a comment. Blotato queues the message and sends it in the background. To check the status, poll with blotato_get_message.
- Input:
accountId(required) - connected account to send from (from blotato_list_accounts)platform(required) -instagramorfacebookpageId(required for Facebook) - the Facebook Page to send from (from the account's subaccounts via blotato_list_accounts)recipientId(required) - the other party's id. Use an incoming message'ssenderId(from blotato_list_messages)text(required) - message body. Instagram messages are limited to 1000 bytes, Facebook to 2000 characters. Withbuttonsset, the limit drops to 640 characterscommentId(optional) - to send a private reply to a comment instead of a direct message, pass the comment's Blotato IDbuttons(optional) - Facebook and Instagram only. 1 to 3 call-to-action buttons pinned under the message. See Buttons and Quick RepliesquickReplies(optional) - Facebook and Instagram only. 1 to 13 tappable reply chips. See Buttons and Quick Replies
- Output: the queued message (poll with blotato_get_message)
- Status values: queued -> processing -> sent | failed
Buttons and Quick Replies
Facebook and Instagram messages may be sent with attached buttons or quick replies via buttons or quickReplies. They are mutually exclusive - pass one or the other, never both.
Buttons sit under the message and stay there. Each has:
type-web_urlopens a link,postbackreports the tap back to youtitle- button label, 1 to 20 charactersurl- required forweb_url, starts withhttps://payload- required forpostback, 1 to 1000 characters
Blotato supports web_url and postback buttons. Phone buttons are not supported.
Instagram renders buttons in the mobile app only. A recipient reading the conversation on instagram.com in a desktop browser sees the message text with no buttons. Pass buttons or a URL inside text, not both, since a message carrying both leaves the URL unclickable on desktop. For a desktop audience, drop buttons and put the URL in text.
Quick replies are tappable chips offered as canned answers. They disappear once the person taps one or types their own message. Each has a title (1 to 20 characters) and a payload (1 to 1000 characters).
Reading a tap. Both kinds of tap arrive as the next incoming message carrying payload.selection, readable with blotato_list_messages. A quick-reply tap sends a real text message, so text holds the chip label. A postback sends no text message: the tap is recorded as an incoming message with text set to the button label. Either way, branch on selection.payload rather than text, since two chips sharing a label are distinguishable only by payload. A web_url button produces no selection.
Reconnect for postback buttons. Blotato subscribes your account to the postback webhook when you connect it. If you connected your account before buttons were launched, reconnect to start receiving postback events. Quick-reply taps need no reconnect.
See Buttons and Quick Replies for the REST equivalent.
Automations
Create and manage DM automations on Instagram and Facebook Pages. An automation sends one direct message when someone comments on your post or sends your account a message. See DM Automations.
An automation sends one message by default. Four optional steps extend it, and Blotato runs them in a fixed order: a follow gate (Instagram only), an email gate, your message, then a webhook. A public reply posts under the triggering comment right after the first message.
Every live automation whose trigger matches starts its own run. Two automations matching the same comment both try to answer it, and only one reply reaches the person. Keep one live automation per keyword on each account. Messages without text, such as photos or stickers, never start a run.
Every DM an automation sends counts toward your plan's monthly active-contacts limit. Gate messages go to the same person, so one contact still counts once. See Active Contacts.
blotato_create_automation
Create a DM automation. It starts as an inactive draft unless isActive is true. You can add an email gate, an Instagram follow gate, or a webhook, and change the public reply to the comment.
- Input:
accountId(required) - Instagram or Facebook account from blotato_list_accountsplatform(required) -instagramorfacebookpageId(required for Facebook) - the Facebook Page from the account's subaccountsname(required) - automation label, 1 to 60 characterstriggers(optional) - up to 2 triggers, at most onecomment-receivedand onemessage-received. Each hastype,keywords(omit or empty to match any comment or text message),postId(comment triggers only, the tracked Blotato post ID, not the native platform ID), andisActive(default true). For an externally published Instagram post already tracked through an incoming comment, use the comment's non-nullpostIdafter verifying the account andplatformPostId. OmittingpostIdmatches any post and requires approval for this scope. See post targeting. Acomment-receivedtrigger fires on top-level comments only, not on replies to comments. Any one trigger firing starts a single run. Omittriggersfor a draft with no triggersdmMessage(required) - the message sent when a trigger fires, 1 to 640 charactersbuttons(optional) - up to 3 link buttons, each withtype: "url", atitleof 20 characters or fewer, and aurlfollowGate(optional, Instagram only) -message(1 to 640 characters) andbuttonTitle(20 characters or fewer, defaultI'm following). Holds the DM back until the contact follows the account. Rejected on a Facebook automationemailGate(optional) -message(1 to 640 characters). Holds the DM back until the contact replies with an email address. On automations published after September 14, 2026, a contact with an email already on file skips itwebhook(optional) -method(GET,POST,PUT,PATCH, orDELETE),url(publichttp(s), 2048 characters or fewer), andheaders(optional). Called once the DM sendscommentReply(optional) -variants, 3 to 6 reply variants, each{ text }, posted publicly under the triggering comment, one picked at random per comment. Each text holds up to 2,200 characters on Instagram and 8,000 on Facebook, counting each{{mention}}as 31.{{mention}}in a text tags the commenter. Omit it for the 3 default replies (Sent to your DMs! Check Message Requests (top right) and tap Accept 📬,Sent! 📩 Two spots to check: your inbox, and Message Requests (sometimes Hidden Requests too),Sent! 🙂 Not in your inbox? Check Message Requests and tap Accept), or pass null to turn the public reply offisActive(optional) - true publishes it immediately. Default false
- Output: the created automation
Follow gate. Blotato sends the gate message with a confirm button, waits up to 30 days for a reply, then reads follower status. A contact who does not follow gets the gate message again. An unknown status sends the DM anyway, since Instagram withholds follower status for a contact who never granted profile access. A confirmed follow is reused for 30 days, but the gate message still goes out on every run.
Any text reply advances the follow gate, so the button tap is a shortcut rather than a requirement. Two setup points to pass on to the user. The Instagram account needs reconnecting if they connected it before DM automations and follow gating landed, since Blotato subscribes to button-tap events at connect time and an older connection does not reliably receive them, leaving runs to expire. Instagram also renders the confirm button in the mobile app only, so write the gate message to ask for a typed reply such as "Reply FOLLOWING once you have" in the message text.
Email gate. Blotato sends the gate message, waits up to 72 hours, and reads the first email address out of the reply. A reply holding no address returns the gate message. A match saves to the contact, then the DM sends. A contact with an email already on file skips the gate, and the DM sends with no gate message. This applies to automations published after September 14, 2026. An automation published earlier asks every time until you pass its current triggers to blotato_update_automation. Use a webhook to export the stored contact email. Conversation and message responses have no dedicated captured-email field, although the original reply remains available as message text.
Public reply. On a comment trigger, Blotato posts one of the commentReply texts under the comment right after the first DM, which is the gate message when the contact gets one. A run started by a DM posts no public reply. When the private reply fails, no public reply posts. A failed public reply fails the run, so no later message goes out, including the DM behind a gate, and the webhook is not called.
Webhook. Every method except GET carries a JSON body with two keys, with or without a gate on the automation: {"email": "them@example.com", "isFollower": true}. email is the address on file for the contact, captured by an email gate, and null when Blotato holds none. isFollower is the follower status a follow gate last recorded, and null when Blotato never checked. GET carries no body. The host must resolve to a public address, redirects are not followed, and the timeout is 15 seconds. A non-2xx response or a timeout gets logged and the run still completes, with no retry. A blocked address, a DNS failure, or a connection error fails the run with error code 20304.
blotato_list_automations
List your DM automations, ordered by creation time (most recent first). Supports cursor-based pagination and selected analytics metrics.
- Input:
limit(optional) - number of automations per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous response
- Output: array of automations with
id,accountId,name,platform,target,triggers(each withid,type,keywords,postId, andisActive),dmMessage,buttons,emailGate,followGate,webhook,commentReply,isActive,publishedVersionId,createdAt,updatedAt, andstats.statscontainstriggered,completed, andfailedcounts from the last 24 hours pluslastRunAt, which is null when the automation has never run. Archived automations do not appear. Includescursorfor the next page when present.
blotato_update_automation
Update a DM automation. Any of name, triggers, dmMessage, buttons, followGate, emailGate, webhook, or commentReply you pass replaces that field. Omitted fields stay unchanged. Pass null to remove a gate or a webhook, or to turn off the public reply. triggers replaces the whole trigger set, and [] removes every trigger.
Content changes to a live automation publish immediately. Changes to a draft stay saved until you pass isActive true. A live automation needs at least one active trigger, so to clear every trigger pass an empty triggers array and isActive false in the same call. To remove one trigger, pass triggers holding the trigger you keep. To update a single trigger without other changes, use blotato_update_automation_trigger.
- Input:
automationId(required) - automation ID from blotato_list_automationsname(optional) - new automation label, 1 to 60 characterstriggers(optional) - replaces every trigger. Up to 2, at most one per type.[]removes alldmMessage(optional) - replaces the message textbuttons(optional) - replaces the link buttons.[]removes allfollowGate(optional, Instagram only) - replaces the follow gate. Pass null to remove itemailGate(optional) - replaces the email gate. Pass null to remove itwebhook(optional) - replaces the webhook. Pass null to remove itcommentReply(optional) - replaces the public reply to the comment. Pass null to turn it offisActive(optional) - true publishes, false moves to draft. Omit to keep the current state
- Output: the updated automation
blotato_update_automation_trigger
Update a single trigger on a DM automation, for example to turn it on or off. The change applies immediately on a live automation, with no republish. At least one trigger must stay on while the automation is live. To pause the whole automation, pass isActive false to blotato_update_automation instead.
Trigger IDs change whenever the automation's content or triggers are updated. Read them from blotato_list_automations or from the automation blotato_update_automation returns.
- Input:
automationId(required) - automation ID from blotato_list_automationstriggerId(required) - trigger ID from the automation'striggersisActive(required) - true turns the trigger on, false turns it off
- Output: the updated trigger
blotato_delete_automation
Archive a DM automation and stop new runs. Existing runs, including waiting gates, remain able to continue. Archiving does not cancel messages already queued. Archive only when requested. The archived automation no longer appears in blotato_list_automations.
- Input:
automationId(required) - automation ID from blotato_list_automations - Output: the archived automation
blotato_list_automation_runs
List the execution runs of one automation, ordered by start time (most recent first). A run is one execution: one comment or message matched a trigger. Use it to check whether an automation fires and why a reply did not go out.
- Input:
automationId(required) - automation ID from blotato_list_automationslimit(optional) - number of runs per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous responsestatus(optional) - array of statuses to include:running,waiting,completed,expired,superseded,failed. Omit to include allsince(optional) - ISO 8601 timestamp. Only runs with activity at or after this time are returned
- Output: array of runs with
id,contactId,platform,status,error(when failed),createdAt, andupdatedAt. A failed run'serrorincludescode,message, and, when available,actionanddetailswith recovery context - Status values: running, waiting, completed, expired, superseded, failed. A run expires when the contact never answers a gate inside its window: 30 days for a follow gate, 72 hours for an email gate. A run also expires when its message never settles within 30 minutes. A run is superseded when a newer run starts waiting on the same contact
blotato_list_automation_logs
List the execution logs written as an automation's runs advance, ordered by creation time (most recent first).
- Input:
automationId(required) - automation ID from blotato_list_automationsflowRunId(optional) - filter to a single run, from blotato_list_automation_runslimit(optional) - number of logs per page. Min: 1, Max: 250. Default: 50cursor(optional) - pagination cursor from a previous response
- Output: array of logs with
id,flowRunId,nodeId,level(info,warning,error),message,context, andcreatedAt
blotato_get_automation_analytics
Get analytics for one automation. triggered, completed, and failed are all-time totals. issues counts runs that failed during the last 7 days and is a subset of failed. A run ending on an error after the DM sends counts as failed. Runs still in flight, and runs ending as expired or superseded, count toward triggered but not toward completed or failed.
- Input:
automationId(required) - automation ID from blotato_list_automations - Output:
triggered,completed,failed,issues
Content Extraction
blotato_create_source
Extract content from a URL or text. Polls internally for up to 20 seconds and returns the result directly. If still processing (e.g., a long YouTube video), returns the source ID -- use blotato_get_source_status to poll for completion.
- Input:
sourceType(required) - youtube, article, twitter, tiktok, text, audio, pdf, or perplexity-queryurl(optional) - required for URL-based source typestext(optional) - required for text and perplexity-query source typescustomInstructions(optional) - guide extraction (e.g., "focus on key takeaways", "summarize in 5 bullet points")
- Output:
idand status. A completed result includestitle,content, andreferenceUrlwhen available. Extraction failure from this create tool is an MCP error containing the source ID.
Long source content ends with [output truncated] when it exceeds the MCP response budget. A completed job does not prove the tool returned the full text. For complete content, use an authorized REST lookup with the same ID. Repeating the MCP status call does not paginate the text. See Extract and repurpose content.
blotato_get_source_status
Check the status of a source extraction. Use this if blotato_create_source timed out and returned an in-progress status.
- Input:
id(required) - source ID from blotato_create_source - Output:
id, status,titleandcontentwhen completed,messagewhen failed. Completed content is subject to the same truncation behavior as the create tool. - Status values: queued -> processing -> completed | failed
An extraction failed result from this status tool is returned in JSON without an MCP isError flag. Inspect status as well as the tool error flag.
Videos and Images
blotato_list_design_templates
List available design templates for images, infographics, carousels, slideshows, and videos.
- Input:
search(optional) - case-insensitive literal text search in template name or description. Regex characters are matched literally.id(optional) - retrieve the exact template ID instead of searching. - Output:
itemscontainingid,description, and availableinputs. Do not depend on atitleornamefield in the MCP result. For names through REST, requestfields=id,name,description,inputs.
Inspect the returned input specification before generation. A template lookup does not create a visual or require a blank generation request. See Inspect inputs without generating.
blotato_create_design
Create an image, infographic, carousel, slideshow, or video from a design template.
- Input:
templateId(required) - from blotato_list_design_templatesinputs(optional) - template-specific values. Use{}with a prompt for a first request.prompt(optional) - describe what you want in natural languagerender(optional, default: true)title(optional) - title for the design
- Output:
item.id(the design ID) anditem.status(poll with blotato_get_design_status)
blotato_get_design_status
Check the status of a design created with blotato_create_design.
- Input:
id(required) - design ID from blotato_create_design - Output:
item.status,item.mediaUrl(videos),item.imageUrls(images/carousels), anditem.errorwhen the design fails - Status values:
queueing,generating-script,script-ready,generating-media,media-ready,exporting,done,creation-from-template-failed,insufficient-credits, ordraft - Stop polling when
item.erroris set, including on an intermediate status. Use media URLs afteritem.statusreachesdone. Wait at least 15 seconds between status calls.
Content Calendar
blotato_list_schedules
List all future scheduled posts, ordered by scheduled time (ascending). Supports cursor-based pagination.
Each schedule includes the draft content (same structure as the post object in blotato_create_post), the scheduled time in UTC, and the target account information.
- Input:
limit(optional) - number of schedules per page. Min: 1, Max: 50. Default: 20cursor(optional) - pagination cursor from a previous response
- Output: array of schedules with ID, scheduledAt, account info, and draft content. Includes
count(total) andcursor(for next page, if present).
blotato_get_schedule
Get a single scheduled post by ID. Returns the full schedule details including draft content, scheduled time, and account info.
- Input:
id(required) - schedule ID from blotato_list_schedules - Output: schedule object with ID, scheduledAt, account, and draft
blotato_update_schedule
Update a scheduled post's content, scheduled time, or both. At least one field is required.
The scheduled time must be a valid ISO 8601 date string in the future. When the time changes, the post is re-queued for publishing at the new time.
To update the post content, call blotato_get_schedule first, then send the full post as a replacement. accountId, platform, and text are required. Fields you leave out are not kept, and leaving out mediaUrls removes the post's media. Omit post to change only the time.
- Input:
id(required) - schedule ID from blotato_list_schedulesscheduledTime(optional) - new ISO 8601 timestamp, must be in the futurepost(optional) - updated post object with accountId, platform, text, mediaUrls, and platform-specific fields
- Output: confirmation message
blotato_delete_schedule
Delete a scheduled post and cancel its publishing job. This action cannot be undone.
- Input:
id(required) - schedule ID from blotato_list_schedules - Output: confirmation message
Media
blotato_create_presigned_upload_url
Get a presigned URL to upload a local file directly to Blotato. No intermediate storage (Google Drive, S3) required.
- Input:
filename(required) - filename with extension, used to determine content type (e.g., "photo.jpg", "video.mp4") - Output:
presignedUrl(URL to PUT the file to, expires after a short period) andpublicUrl(the final public URL to use in blotato_create_post) - Max file size: depends on your plan (see Plan Limits)
- Rate limit: 120 requests per minute
How to use:
- Call
blotato_create_presigned_upload_urlwith your filename - PUT the file contents to the returned
presignedUrlwith the correct Content-Type header - Use the returned
publicUrlin blotato_create_post'smediaUrlsfield
If your media is already at a public URL, you don't need to upload it first -- pass the URL directly into blotato_create_post's mediaUrls field. The presigned upload tool is for local files that don't have a public URL yet.
Accounts and identifiers
Get IDs from Blotato responses. A username, profile URL, or native platform post ID does not replace a Blotato ID.
Select an account
- Call
blotato_list_accountsthrough MCP, orGET /v2/users/me/accountsthrough REST. - Match the returned platform and account name to the user's intended destination.
- Use the returned account
idasaccountId. - Select any required Page, board, or playlist from the lookups below.
If several accounts match, ask which account to use. If none match, direct the user to Accounts.
After disconnecting and reconnecting an account, retrieve the current ID before retrying. A saved workflow or brand mapping might contain a stale ID. Confirm the account belongs to the same authenticated Blotato user and platform as the request.
| Destination | Identifier | Where to get it |
|---|---|---|
| Facebook Page | pageId, required | MCP account subaccounts, or REST GET /v2/users/me/accounts/:accountId/subaccounts |
| LinkedIn company Page | pageId, required for this destination | MCP account subaccounts, or the REST subaccounts endpoint |
| LinkedIn personal profile | Omit pageId | Use the LinkedIn accountId |
| Pinterest board | boardId, required | blotato_list_pinterest_boards, or GET /v2/social/pinterest/boards?accountId=... |
| YouTube playlist | playlistIds, optional | MCP account subaccounts, or the REST subaccounts endpoint |
A returned Facebook Page is a destination to select, not permission to publish to the first Page in the list. LinkedIn Page IDs apply only when the user chooses a company Page. Omitting pageId selects the LinkedIn personal profile, not a company Page. Omit YouTube playlistIds unless playlist placement is requested.
MCP's requiredFields includes hints, not the customer's destination selection. Match the requested Page against subaccounts. An empty subaccount list does not prove the platform account has no Pages, since lookup failures also need investigation. Stop if a required destination ID is unavailable.
Account not found
This error means the submitted ID did not match an account for the authenticated Blotato user and requested platform. It does not establish which value is wrong.
- Read the failed request's
accountId,content.platform, andtarget.targetType. - Retrieve accounts using the same credential or MCP connection used for publishing.
- Select the returned account for the user's intended platform and destination.
- Retrieve a separate Page ID when required. Do not put a Page ID in
accountId. - Update the saved workflow mapping if it contains an old ID.
Different credentials, an ID from another platform, a Page ID used as an account ID, and an ID saved before reconnection are separate checks. An account dropdown reduces manual copying but does not guarantee a saved selection is current. An AI assistant must perform the lookup rather than assume it happened automatically.
Reconnect only when the connection state or returned error calls for it. If the same ID, platform, and authenticated user still produce the error after a fresh lookup, retain the request details and escalate. Do not assert a key mismatch without checking it. Never include keys or tokens in an escalation.
Before sending another publish request, verify the earlier submission's outcome through Publishing status.
Keep post IDs separate
| ID | Use |
|---|---|
postSubmissionId from create-post | Poll publishing status with blotato_get_post_status or GET /v2/posts/:postSubmissionId |
| Published post ID from post listings | Fetch analytics or comments for the published post |
Scheduled post id from schedule listings | Get, update, or cancel the scheduled post |
Source id | Check source extraction |
Visual item.id | Check visual generation |
Comment id | Fetch the comment or check reply completion |
Conversation or message id | Fetch the corresponding conversation or message |
| Automation flow and trigger IDs | Manage the automation or a trigger |
For blotato_list_posts, inspect each item's state. A scheduled item and a published item describe different records. Read the List Posts response before passing an ID to another operation.
Updating an automation's content or triggers reissues its trigger IDs. Read the returned triggers before updating a trigger. See DM automations.
Full lookup shapes: Accounts, Scheduled posts, Comments, and Messages.
Async jobs and polling
Publishing, source extraction, visual generation, comment posting, and message sending finish after the initial request. Save the returned ID and check the operation's status before reporting success.
Completion rules
| Operation | Status lookup | Completion |
|---|---|---|
| Immediate post | blotato_get_post_status or GET /v2/posts/:postSubmissionId | published succeeds. failed stops the workflow. in-progress needs another check. |
| Scheduled post | Create response, then schedule lookup when needed | Report the returned scheduledTime. scheduled means scheduled, rather than published. |
| Source | blotato_get_source_status or GET /v2/source-resolutions-v3/:id | completed succeeds. failed stops the workflow. queued and processing need another check. |
| Visual | blotato_get_design_status or GET /v2/videos/creations/:id | item.status: done supplies finished media. Stop on item.error, creation-from-template-failed, or insufficient-credits. |
| Comment | blotato_get_comment or GET /v2/comments/:commentId | posted succeeds. failed stops the workflow. |
| Message | blotato_get_message or GET /v2/messages/:messageId | sent succeeds. failed stops the workflow. |
MCP timing
blotato_create_post waits internally for up to 20 seconds for immediate publishing. blotato_create_source also waits internally for up to 20 seconds. If either returns unfinished work, use its status tool with the same ID.
- Wait at least 10 seconds between post or source status calls.
- Wait at least 15 seconds between visual status calls.
- For queued comments and messages, space status checks to stay within the endpoint rate limits.
- When the agent's execution window ends, retain the ID and report processing status. Resume with a status lookup rather than another create request.
Inspect both MCP isError and the operation's status. A post or source status lookup returning failed is still a failed job even when the tool call itself succeeded. Source status failures use message. Post status failures use errorMessage.
Post in-progress is a fallback when no matching result record is found, not an independent queue-health check. Verify the saved submission ID and use a bounded polling loop. See post lifecycle.
REST timing
REST create calls return a submission or creation response. The caller manages status checks. Use the intervals above as polling guidance and respect any rate-limit response. A 201 response confirms acceptance, rather than downstream publication.
Visual states
Visual generation uses queueing, generating-script, script-ready, generating-media, media-ready, and exporting before done. Not every template traverses every state.
Inspect item.error on every response. A visual with an error has stopped even if its status remains script-ready or another intermediate state. draft is not a finished rendered visual. Follow Create Visual when choosing render and template inputs.
Use item.mediaUrl or item.imageUrls only after generation succeeds. Those URLs are ready for publishing and do not need a separate upload.
Uploads are a separate flow
A presigned upload response provides 2 URLs. Upload the file bytes to presignedUrl, wait for the upload to succeed, and use publicUrl. There is no upload-status MCP tool. See Media uploads and conversion.
For examples, see Workflow recipes. For failure recovery, see Errors and retries.
Media uploads and conversion
Choose the input flow before publishing. Uploading a file and converting it to meet a platform's requirements are separate operations.
| Your input | Next action |
|---|---|
| Public image or video URL | Pass it directly in mediaUrls. No upload step required. |
| Finished Blotato visual | Pass the returned mediaUrl or imageUrls. No upload step required. |
| File on the user's computer or in the agent's workspace | Complete a presigned upload, then pass publicUrl. |
| Private download link or editor/share page | Obtain a public downloadable media URL, or upload the file bytes. |
Upload a local file
- Call
blotato_create_presigned_upload_urlwithfilename, including its extension. For REST, callPOST /v2/media/uploadswith the same field. - Send an HTTP
PUTto the returnedpresignedUrl, with the raw file bytes as the request body. - After the upload succeeds, pass the returned
publicUrlin the publish request'smediaUrlsarray.
The PUT body is raw bytes. Do not send JSON or multipart form data. The assistant needs access to the file and an HTTP tool or shell to perform the PUT. Creating the URL alone does not upload the file.
If the assistant's environment blocks the upload destination, follow the MCP network-egress troubleshooting. For REST upload shapes, see Upload Media.
Check conversion requirements
Blotato validates media for the destination platform and performs supported conversions when required. Automatic video conversion is limited to videos no longer than 120 seconds. A longer video must already meet the applicable publishing requirements.
The processing queue checks the original file and existing variants. It reuses a valid file without conversion. If none is valid, it either requests a supported conversion of the original or returns the validation error. File upload does not imply every file is converted.
- Check the platform media requirements.
- Check the file's container, codecs, dimensions, aspect ratio, duration, bitrate, and size.
- If a video longer than 120 seconds needs cropping, resizing, or re-encoding, edit and export it before publishing.
- Use a URL which serves the media without a login.
- Submit the post and check its final publishing status.
An .mp4 filename does not prove the container, codecs, or aspect ratio. Upload success does not establish platform compatibility.
For Instagram Reels, see the Reel troubleshooting checklist. Account upload limits and platform file limits both apply. See Billing and credits and Media requirements.
Container identification errors
Unsupported media format: mov,mp4,m4a,3gp,3g2,mj2 means Blotato did not recognize the file's container brand. The listed formats describe the probe's format family, not the file's exact type. This error is separate from the 120-second conversion limit.
- Inspect the file's container metadata, including
major_brand. Do not identify the format from its filename alone. - Export the source as MP4 with H.264 video and AAC audio. Renaming the extension does not change the container.
- Inspect the exported file and check its dimensions, bitrate, size, and duration against the destination's requirements.
- Verify the original submission's status before retrying. If the error persists, provide support with the submission ID and the exported file's metadata. Keep signed URLs and credentials out of support messages.
For the agent: the current parser recognizes MP4 brands isom, iso1 through iso6, mp41, and mp42. It recognizes MOV through the exact padded brand qt . Missing or unrecognized brands produce the format-list error, even for a short video. A recognized container does not prove publishing compatibility.
Post lifecycle
A post moves through submission, processing, and a published or failed outcome. Scheduling adds a wait until the chosen time.
| Result | Meaning | Agent response |
|---|---|---|
Create response with postSubmissionId | Blotato accepted the request | Save the ID |
in-progress | No failed, published, or scheduled result was found | Verify the saved submission ID and poll within a waiting limit |
scheduled | The post is scheduled | Report scheduledTime and stop immediate polling |
published | Publishing completed | Return publicUrl when supplied |
failed | Publishing stopped | Explain errorMessage and resolve the cause |
Publish now
- Fetch the destination account and required IDs.
- Submit the post once.
- Follow status polling.
- Report the returned outcome.
Publish later
- Resolve the user's requested date, time, and timezone.
- Submit with a future
scheduledTimeoruseNextFreeSlot: true. - Report the resolved UTC time in the user's timezone.
- Use scheduled-post management for later edits or cancellation.
Do not keep polling a future scheduled post as if publication should finish now. Check publication after its scheduled time when the task requires it.
Look up existing work
Use List Posts to inspect published, scheduled, and failed records. Its state.type values describe list items, while the submission-status endpoint uses the status values above.
Keep submission, scheduled, and published post IDs separate. A retry after an uncertain network result starts with looking up existing work. Repeating create-post risks a duplicate.
The submission-status endpoint does not verify a live queue job before returning in-progress. This fallback also applies when it finds no record for the supplied ID. Use the ID from the original create response and the original Blotato account credentials. Do not treat an arbitrary ID returning in-progress as evidence of accepted work. For missing or conflicting records, follow Find a post's outcome before retrying.
Scheduling posts
Choose a specific publish time or the next free calendar slot, not both. An explicit scheduledTime does not bypass slot validation if useNextFreeSlot is also true. A scheduled result confirms the queue entry. Check publication after the chosen time if your workflow needs the live post URL.
Choose a time
- Resolve the user's date, time, and timezone. Ask for the timezone when it is unknown.
- Convert the chosen instant to a future UTC ISO 8601 timestamp, such as
2030-06-15T15:00:00Z. Replace example dates with the intended future date. - Set
scheduledTimein the create-post request. - Read the returned
scheduledTimeand report it in the user's timezone.
For MCP, scheduledTime is a tool argument. For REST, it is a top-level sibling of post:
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "twitter",
"text": "Scheduled post example",
"mediaUrls": []
},
"target": { "targetType": "twitter" }
},
"scheduledTime": "2030-06-15T15:00:00Z"
}
The API parses and returns scheduled times in UTC. There is no separate timezone field in this create-post request. The web calendar's timezone setting controls the calendar experience.
Use the next free slot
- Set up the calendar's schedule slots.
- Set
useNextFreeSlot: truein place of a specificscheduledTime. - Report the resolved time returned by Blotato.
If no matching slot or available time is found, post creation returns a validation error. Add or correct slots for the intended platform, account, and Page. Do not retry without scheduling fields unless the user authorizes immediate publishing.
In REST, useNextFreeSlot is a top-level sibling of post. For slot definitions and advanced REST scheduling, see Weekly posting schedule and Publish Post.
Edit or cancel a scheduled post
- List schedules with
blotato_list_schedulesorGET /v2/schedules. - Read the selected scheduled post with
blotato_get_scheduleorGET /v2/schedules/:id. - Update it with
blotato_update_scheduleorPATCH /v2/schedules/:id, or cancel it withblotato_delete_scheduleorDELETE /v2/schedules/:id. - Check the returned state or re-read the schedule to verify the change.
Use the scheduled post's ID from the schedule listing. See Scheduled Posts for update fields and preserved content.
API rate limits
Blotato applies route-specific request limits. These limits are separate from subscription limits, credits, and social platform publishing limits.
| Operation | Requests per minute |
|---|---|
| Create post | 30 |
| List posts or get post submission status | 60 for each route |
| Get post analytics | 60 |
Upload media from a URL with POST /v2/media | 30 |
| Create a presigned upload URL | 120 |
| List Pinterest boards | 45 |
| List comments or get a comment | 60 for each route |
| Post a comment | 30 |
| List conversations, get a conversation, list messages, or get a message | 60 for each route |
| Send a message | 30 |
| List or get DM automations, runs, logs, or analytics | 60 for each route |
| Create, update, delete an automation, or update a trigger | 30 for each route |
This table covers the listed routes. Consult each endpoint's reference for other limits. MCP tools call the underlying REST routes, so status polling and tool sequences consume requests too.
Handle a limit response
- Stop requests to the limited route after
429. - Wait for the retry interval when the response supplies one.
- Reduce concurrency and request frequency before resuming.
- Use polling intervals rather than repeated status calls without a delay.
A platform publishing restriction is a different limit. For example, the Starter plan's TikTok restriction counts 3 distinct TikTok accounts posted to during a rolling 24-hour window. It is not an API request-per-minute limit or a count of connected accounts. See TikTok limitations.
For credit purchases, see the limits in Buy Credits.
Errors and retries
Read the returned error before changing the request. For REST requests, record the HTTP status and response body. For MCP, inspect the tool result and its isError flag. A request accepted by Blotato still needs its workflow's completion check.
For customer support, use Diagnose and answer to preserve the client, failing stage, previous attempts, and human corrections. Do not repeat a setup question already answered in the conversation.
For missing, delayed, or duplicate posts, follow Find a post's outcome before retrying. An HTTP status or an inaccessible platform URL alone does not establish the underlying cause.
| Error or symptom | Next step |
|---|---|
401, invalid API key, or invalid session | Follow authentication checks |
Subscription-related 403 | Check Billing |
404 | Re-fetch the record and verify the ID type and account |
Validation error, often 422 | Correct the named field using the endpoint schema |
429 | Wait for the retry interval if provided, then reduce request frequency |
Network error or 5xx on a read | Retry with a delay and a bounded attempt count |
| Network error after a create request | Check existing work before submitting again |
Post status failed | Read errorMessage and the platform requirements |
Visual response contains item.error | Stop polling and explain the generation error |
| Empty analytics or inbox result | Check the feature's sync timing and supported platforms or inbox setup |
| Media fetch or conversion failure | Follow the media checklist |
Inspect a failed request
- Open the Logs.
- Select the request.
- Read its payload, response, and error message.
- Correct the cause before resubmitting.
For n8n requests, the dashboard's FIX MY AUTOMATION action helps repair the workflow. See the n8n walkthrough. This action is specific to n8n.
Retry without duplicating work
- Save every submission or creation ID returned by a successful create request.
- If a status call fails, retry the status call with the saved ID.
- If creation timed out without an ID, inspect the dashboard and existing posts or schedules before creating another item.
- For a failed post, correct the error before a new submission. An unchanged retry often fails for the same reason.
- Set an attempt or elapsed-time limit in your automation. Report unfinished work and its ID when the limit is reached.
Blotato does not expose a documented client-supplied idempotency header for create-post requests. Internal duplicate detection is not a guarantee for arbitrary changed payloads, times, or retries. Retain the submission ID, inspect existing work, and do not invent an idempotency header.
See Error reference, API FAQs, MCP FAQs, and Get support for specific cases.
Diagnose and answer a support question
Scope: support agents answering questions about the website, MCP, REST, n8n, or Make. Customer assistants use the same checks before retrying a failed operation.
Response contract
- Answer the question using the context already supplied.
- Give the next supported action for the customer's surface.
- State what proves success or what remains unresolved.
- Link the relevant section. A tutorial supplements the answer, not replaces it.
Do not ask a basic setup question again when the customer already answered it. Preserve the exact error, attempted steps, and human support corrections. A historical incident or an empty result does not prove a current outage.
Identify the stage
| Customer symptom | Checks before the next action | Evidence or stop condition |
|---|---|---|
| “Connected”, but no tools | Identify the client. Separate connector creation, authorization, callback, and tool discovery. Use client setup. | A successful account-list call verifies authentication. A redirect alone does not. |
| API key rejected | Check the provider, endpoint, header, full key, and paid-access state using authentication checks. Never request the secret in chat. | Stop repeated writes. Record the sanitized error and HTTP status. |
| Account not found, wrong account, or reconnected account | Re-list accounts and match platform, name, and destination. Retrieve Page or board IDs where required. See identifier rules. | No unambiguous matching destination means no publishing action. |
| “Upload failed” | Identify whether the artifact is workflow JSON or media. For media, distinguish local bytes, signed upload, Blotato fetching a host, and platform validation. | Use media diagnosis, not a generic reconnect instruction. |
| “Automatic upload isn't possible” or “no media library” | Separate reusable web-app storage from API/MCP uploads. Identify the client's file access and HTTP upload capability. Use the local media upload and client setup guides. | The absence of a reusable media library does not block automated upload or publishing. Do not substitute generated visuals when the customer asks to post existing files. |
| Accepted request, but nothing published | Retrieve the saved submission ID with post status. Inspect status and error fields. For missing or conflicting records, use publishing-status diagnosis. | Scheduled is not published. Unknown outcome is not permission to create again. in-progress alone does not prove a live queue job. |
| Generation failed despite credits | Inspect the visual's error and template inputs. Check complete-job cost, not only a per-scene price. | Use visual failure diagnosis. Do not infer the cause from a terminal status alone. |
| Missing post drafts | Check the AI Agent and Remix. Distinguish post drafts from Videos projects. | Use draft-finding steps. Apply the same-browser limitation only after confirming an AI Agent draft and a device or browser change. An empty AI Agent list does not prove the draft is lost. |
| Edit, mute, download, or post an existing video | Open the existing visual. Distinguish track audio, caption narration, preview state, export, and post draft. | Use Edit, mute, and export. Create Post is not publication. Do not regenerate to solve a download question. |
| Empty analytics or inbox | Check the operation's platform support, permissions, post eligibility, and collection timing. | Analytics and Inbox have different collection rules. Missing data is not 0 engagement. |
| Cancellation, refund, discount, or paid-but-inactive | Separate published policy from the customer's verified subscription and payment state. | Use billing policy. Account changes need authorized execution and a confirmed result. |
Media upload and conversion
Scope: existing image or video files, not n8n workflow JSON or generated-template records.
- Identify where the file exists: the customer's device, the assistant's workspace, or a remote URL.
- For local media, verify the assistant has file access and an HTTP upload tool. A presigned URL alone does not upload bytes.
- For a client sandbox error, inspect the blocked host and client policy. Do not apply client allowlist instructions to a remote host rejecting Blotato's servers.
- For remote media, verify a direct file response without interactive login. Browser access alone does not prove server-to-server access.
- Inspect the actual container, codecs, file size, duration, and dimensions. An
.mp4extension is not a metadata probe. - Apply conversion and platform requirements. A video longer than 120 seconds is not automatically prohibited, but must already satisfy the destination's requirements.
- After correction, verify the publishing result. Upload success does not prove publication.
Repeated failure or unclear cause
- Carry forward completed checks and their results. Do not resend the same checklist without new evidence.
- Record the client or integration, operation, destination platform, timestamp and timezone, request/submission/visual ID, exact error, and sanitized request shape.
- Record expected versus observed behavior and attempted fixes.
- Stop if the next action risks another charge, duplicate post, wrong destination, or unauthorized account change.
- Use Get support with the evidence. Do not include API keys, OAuth codes, signed upload URLs, or unrelated customer data.
For a capability question with a confirmed answer, answer it directly. For example, Facebook publishing targets a Page, not a personal profile. Do not send setup tutorials or ask the customer to reconnect for an unsupported destination.
This page does not change support-ticket closure rules or grant tools permission to modify accounts.
Find a post's outcome before retrying
Use this page when a post disappears from Upcoming Posts, remains in progress, shows published without a visible post, or appears twice. These symptoms do not establish the cause.
Using the Blotato website
- Record the intended social account or Page, content, and submission or scheduled time with timezone.
- Check the Scheduled, Published, and Failed filters in Posts for the same destination and content. Check the platform and time-window filters if a record is missing.
- Open any returned platform URL and check the intended account on the platform.
- Read the exact error before changing media, reconnecting an account, or retrying.
- If those records do not establish the result, contact support with the evidence below. Do not submit a replacement while the original outcome is unknown.
Using MCP, REST, n8n, or Make.com
- Retrieve the
postSubmissionIdfrom the original create response. Do not substitute a schedule ID, published-post ID, or guessed UUID. - Call
blotato_get_post_statusor Get Post Status with that ID and the original Blotato account credentials. - Follow the status-specific completion rules.
- Inspect existing posts and schedules when the submission result is missing or inconsistent.
- Retain the ID when your polling limit is reached. Escalate the unresolved result instead of repeating create-post.
The status endpoint returns in-progress when no matching failed, published, or scheduled record is found. It does not independently confirm a live queue job. A wrong or unavailable submission ID is not proven valid by this status. Verify the original create response before further polling.
Interpret the evidence
| Observation | Supported conclusion and next step |
|---|---|
| Schedule disappeared at its due time | The schedule is no longer in that list. Check publishing results before assuming failure or success. |
| Published record, but platform URL is absent or inaccessible | Blotato recorded publication. Check the destination and platform account. An inaccessible URL alone does not prove moderation, deletion, or suppression. |
| Failed result | Read the error and check the destination before retrying. Correct an identified validation or connection problem. Retry a temporary failure only after checking for an existing post. |
| 2 copies on the platform | Record both URLs and submission times. Do not infer a timeout or blame a particular client without request evidence. Ask which copy to keep before removing content through the platform. |
| Several accounts fail at once | Investigate a shared service or incident. This pattern alone is not proof of an outage or its owner. |
Escalation evidence
Include the client, destination, exact error, timestamps with timezone, postSubmissionId when available, relevant request/reference IDs, and platform URLs. State which checks are already complete. Switch to Developer Platform and open Logs for recorded activity. Filter by Posts, Videos, Media, Accounts, or DM, then Processing, Failed, or Success. Search or filter by platform and account. Absence from a filtered log list does not prove no publishing attempt occurred.
Do not share API keys, OAuth codes, or signed upload URLs. Do not promise incident compensation or report a refund, credit adjustment, deletion, or reconnection as completed without confirmation.
Publish and verify a post
Scope: external assistants using MCP or REST, including n8n and Make HTTP requests. Publishing requires paid access, a connected social account, and the user's authorization for the content and destination. For website actions, use Create posts.
Prompt for your assistant:
Publish this post to my selected Blotato account. First list my accounts and confirm the destination from my request. Check the platform requirements, submit the post, and return its final status and public URL.
Using MCP
The following text-only X example illustrates the complete path. Replace example IDs and text with the customer's requested destination and approved content. Other platforms have different requirements.
- Call
blotato_list_accountswith{"platform":"twitter"}. The result is an account array, not REST'sitemswrapper:
[
{
"id": "98432",
"platform": "twitter",
"fullname": "Example account",
"username": "example",
"subaccounts": [],
"requiredFields": {}
}
]
- Match the requested account. An empty list confirms authentication but requires connecting an account in Accounts. Multiple matching destinations require clarification before a write.
- Call
blotato_create_post:
{
"accountId": "98432",
"platform": "twitter",
"text": "Approved post text.",
"mediaUrls": []
}
- Read the tool result, including
isError,status, and any error text. If processing continues, retainpostSubmissionIdand callblotato_get_post_statusat least 10 seconds later:
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
- Follow the result table below. The create tool waits internally for up to 20 seconds. It might return a completed result without another status request. Do not submit the same post again to check progress.
Adapt the destination
- Call
blotato_list_accountsto findaccountIdand any Page IDs. - Read the destination's platform guide. For Pinterest, call
blotato_list_pinterest_boardsto getboardId. - Supply public media URLs, or complete the local upload.
- Call
blotato_create_postwith the account, platform, content, and required platform fields. - If the returned status is
in-progress, callblotato_get_post_statuswith the returnedpostSubmissionId, waiting at least 10 seconds between checks. - Return
publishedand the suppliedpublicUrl, or explainfailedand itserrorMessage.
The create tool waits internally for up to 20 seconds. Another create call starts another submission. Continue unfinished work with the status tool.
Using REST
- Fetch
GET /v2/users/me/accountsand any required subaccounts or Pinterest boards. - Send
POST /v2/postsusing the Publish Post schema. - Save
postSubmissionIdfrom the response. - Poll
GET /v2/posts/:postSubmissionIdaccording to the completion rules.
Set post.content.platform and post.target.targetType to the same platform. Each create request has one account and destination.
Complete REST example
- Send
GET https://backend.blotato.com/v2/users/me/accounts?platform=twitterwith theblotato-api-keyheader. Select the matchingitems[].idasaccountId. - Send this body to
POST https://backend.blotato.com/v2/postswith the same auth header andContent-Type: application/json:
{
"post": {
"accountId": "98432",
"content": {
"platform": "twitter",
"text": "Approved post text.",
"mediaUrls": []
},
"target": { "targetType": "twitter" }
}
}
- Save the accepted response's
postSubmissionId:
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
- Send
GET https://backend.blotato.com/v2/posts/a1b2c3d4-e5f6-7890-abcd-ef1234567890with the auth header. Use the ID from step 3, not the example ID. Wait at least 10 seconds between status requests.
Completion and recovery
The status endpoint returns the same state vocabulary used by the MCP status tool:
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "published",
"publicUrl": "https://x.com/example/status/123456"
}
| Result | Agent action |
|---|---|
published | Report success and the returned publicUrl when supplied. Do not construct a guessed URL. |
failed | Stop. Read errorMessage, correct the cause, and obtain authorization for any new submission outside the original request. |
in-progress | Poll the saved ID with a waiting limit. Report the ID and unresolved state if the limit is reached. |
scheduled | Report the returned scheduledTime. Do not describe it as published. |
| No response or an uncertain write | Inspect the Logs and existing work before creating again. |
For media, complete upload and validation before creating the post. For Instagram, Facebook, TikTok, Pinterest, YouTube, or LinkedIn, use the platform-specific request, including required media and destination fields.
Cross-post
- Select the accounts requested by the user.
- Adapt the media and target fields for each platform.
- Create a separate submission for each destination.
- Track each submission ID and report each outcome separately.
A success on one platform does not establish success on another. For publishing later, use Scheduling.
Schedule and manage posts
Prompt for your assistant:
Schedule this post for the date, time, and timezone I specify. Use my selected account, then show the resolved publish time. If I ask to change a scheduled post, find and update the existing schedule.
Create a schedule
- Call
blotato_list_accountsand select the destination. - Resolve the requested date and timezone, or choose the next free slot.
- Call
blotato_create_postwithscheduledTimeoruseNextFreeSlot: true. - Verify the resolved
scheduledTimeand report it in the user's timezone. If no time is returned, retrieve status using the savedpostSubmissionIdbefore promising a schedule.
For REST, use POST /v2/posts with scheduling fields beside post. Follow Scheduling posts for the request layout and UTC rules.
Request and verification example
Use an authenticated connection. For “June 15, 2030 at 9 AM in America/Denver,” the resolved UTC time is 2030-06-15T15:00:00Z. Replace this example with the user's intended future date, accounting for daylight saving time on that date. Replace accountId with the selected Twitter/X account from lookup.
Call blotato_create_post once:
{
"accountId": "98434",
"platform": "twitter",
"text": "Registration for our workshop opens today.",
"mediaUrls": [],
"scheduledTime": "2030-06-15T15:00:00Z"
}
For REST, send this body to POST https://backend.blotato.com/v2/posts with blotato-api-key: YOUR_API_KEY and Content-Type: application/json:
{
"post": {
"accountId": "98434",
"content": {"platform": "twitter", "text": "Registration for our workshop opens today.", "mediaUrls": []},
"target": {"targetType": "twitter"}
},
"scheduledTime": "2030-06-15T15:00:00Z"
}
Save the returned postSubmissionId. A REST acceptance response has this shape:
{
"postSubmissionId": "123e4567-e89b-12d3-a456-426614174000",
"scheduledTime": "2030-06-15T15:00:00Z"
}
If further verification is needed, call blotato_get_post_status with {"postSubmissionId": "RETURNED_ID"}, or request GET /v2/posts/RETURNED_ID with the authentication header. A scheduled result has this shape:
{
"postSubmissionId": "123e4567-e89b-12d3-a456-426614174000",
"status": "scheduled",
"scheduledTime": "2030-06-15T15:00:00Z"
}
Report “Scheduled for June 15 at 9 AM America/Denver,” not “Published.” For an unfinished result, wait at least 10 seconds between status checks and stop after a client wait budget, such as 2 minutes, with the saved ID and unresolved state. An uncertain result is not permission to create another post.
Change or cancel
- Call
blotato_list_schedulesto locate the scheduled item. - Call
blotato_get_scheduleto read its content and time. - Call
blotato_update_schedulewith the intended change, orblotato_delete_scheduleto cancel. - Verify and report the resulting schedule state.
For REST, use the corresponding GET, PATCH, or DELETE /v2/schedules/:id operation. See Scheduled Posts.
Scheduled-post IDs differ from submission and published-post IDs. Obtain the schedule ID from the listing. A scheduled result is the stopping point for this task. Publishing verification belongs after the scheduled time.
Stop conditions and batches
Do not assume the create response has status: "scheduled". A returned submission ID or a successful HTTP response alone does not establish the resolved schedule. Use the scheduling rules and post status.
Before useNextFreeSlot, verify slots exist for the intended destination. If no matching slot or available slot time is found, post creation returns a validation error. Do not remove the scheduling field and retry, since a request without scheduling publishes immediately.
For a batch, record each destination, resolved time, submission ID, schedule ID when available, and outcome. Retry only a confirmed failed item after correcting its cause. Do not recreate successful items because another item failed. Scheduling a set of posts does not create a recurring content-generation automation.
Upload local media
Scope: an existing image or video file. This is not the import flow for an n8n workflow template and does not create a generated Visual in the Videos library.
Prompt for your assistant:
Upload this file to Blotato using a presigned upload URL. Send the raw bytes with HTTP PUT, confirm upload success, and use the returned public URL for my post.
- Ensure the assistant has access to the file in its workspace.
- Call
blotato_create_presigned_upload_urlwith the filename and extension. - Upload the bytes to
presignedUrlwith an HTTP PUT. - Use
publicUrlinblotato_create_postafter the upload succeeds. - Follow publishing verification.
For REST, create the upload URLs with POST /v2/media/uploads. The upload itself goes to the returned signed URL, rather than to the REST API endpoint.
Request and result
Call blotato_create_presigned_upload_url with this argument, or send it as JSON to POST https://backend.blotato.com/v2/media/uploads with the blotato-api-key header:
{
"filename": "video.mp4"
}
The response contains presignedUrl and publicUrl. Preserve the returned values. Do not derive one URL from the other or share the signed URL in a support reply.
- Send
PUTtopresignedUrlwith the raw file bytes. Do not use JSON or multipart form data. - Check the upload response for success before using
publicUrl. - Confirm the file meets the plan and platform limits.
- Pass
publicUrlin the publish request'smediaUrlsarray. - Verify the submission's final state separately.
If the client blocks the upload host, resolve the client permission or use a supported environment. If Blotato cannot fetch a remote source, inspect the source host's response instead. These are different request directions. See stage-based diagnosis.
If the file already has a public download URL, pass it directly in mediaUrls. No upload step required. If the assistant lacks file or HTTP access, use a client with those capabilities or provide a public media URL.
See Media uploads and conversion, Upload Media reference, and MCP upload troubleshooting.
Create and publish a visual
Scope: external API/MCP visual generation, including n8n and Make. The in-app AI Agent's video restriction is not a restriction on this workflow. Generation consumes credits according to the requested job. Confirm authorization before starting a new paid attempt.
Prompt for your assistant:
Find a Blotato template for the image, carousel, or video I describe. Read its inputs, generate the visual, and check its status until it finishes or returns an error. Show me the finished media before following my publishing instructions.
Using Blotato API or MCP
- Call
blotato_list_design_templates, orGET /v2/videos/templates, to select a template and inspect its inputs. - Call
blotato_create_design, orPOST /v2/videos/from-templates, withtemplateId, template-specificinputs, a prompt when needed, andrender: truefor rendered output.
Use the exact template ID returned by the listing. Do not strip a path ID to its UUID. MCP's template listing supplies id, description, and inputs. For REST, request fields=id,name,description,inputs when you need the template name and input schema.
- Save the returned
item.id. - Call
blotato_get_design_status, orGET /v2/videos/creations/:id, at least 15 seconds apart. - Stop when
item.statusisdone, or whenitem.erroror a failure state appears. - Use the returned
item.mediaUrloritem.imageUrlsfor the publish workflow.
Do not invent template input fields. Use the template's current schema. Inspect inputs without generating instead of running a blank generation request. Generated media URLs do not need another upload. The completed visual has not been posted to a social platform until the publish workflow succeeds.
See Create Visual, Get Visual Status, and the template catalog.
Request and output example
- Retrieve templates and inspect the current inputs. The following quote-card template is an example, not a substitute for choosing the customer's requested output. Keep the complete template ID.
- Call
blotato_create_designwith this shape. For REST, send the same body toPOST https://backend.blotato.com/v2/videos/from-templateswithContent-Type: application/jsonand theblotato-api-keyheader:
{
"templateId": "/base/v2/quote-card/77f65d2b-48cc-4adb-bfbb-5bc86f8c01bd/v1",
"inputs": {
"title": "Daily practice",
"quotes": ["Practice the skill you want to improve every day."],
"aspectRatio": "4:5"
},
"render": true
}
- Save
item.idfrom the response. Aqueueingstatus means accepted, not finished:
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "queueing"
}
}
- Call
blotato_get_design_statuswith{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}, orGET /v2/videos/creations/a1b2c3d4-e5f6-7890-abcd-ef1234567890. Substitute the saved ID and wait at least 15 seconds between checks. - On
done, read the returneditem.imageUrlsfor image outputs oritem.mediaUrlfor video. Do not guess the URL or reuse the source input as the generated result. - Stop on
item.error,creation-from-template-failed, orinsufficient-credits. A draft orscript-readyrecord without completed media is not ready to publish. Inspect visual status for next steps. - Review the output before a separate publish request. Use the returned URLs directly without another upload.
Set a waiting limit. If generation remains unfinished, return its ID and current state. Do not create another paid job because a status request failed or time elapsed. For a brand requirement, follow Brand Kit because REST and MCP expose different fields.
Using Blotato Web App
- Follow Make your first AI video to choose a template and generate a visual.
- Review the finished output.
- Follow the recommended workflow to publish it.
For images, see AI Images. For credit questions, see Video FAQs.
Extract and repurpose content
Prompt for your assistant:
Extract the content from this source with Blotato, then adapt it for the social platforms I choose. If a platform needs media, use media I supply or generate a visual before publishing.
Before starting
Use an authenticated connection. Choose sourceType explicitly. Use text for text or perplexity-query, and url for article, YouTube, Twitter/X, TikTok, audio, or PDF sources. A URL alone does not choose the source type.
MCP example
- Call
blotato_create_sourcewith the user's source. This example uses supplied text and requires no external source URL.
{
"sourceType": "text",
"text": "Our workshop opens on October 15. Registration closes on October 10."
}
- Save the returned
id. The tool waits internally for up to 20 seconds. If the result is stillqueuedorprocessing, callblotato_get_source_statuswith this shape, replacing the example ID.
{"id": "123e4567-e89b-12d3-a456-426614174000"}
REST equivalent
Send the following body to POST https://backend.blotato.com/v2/source-resolutions-v3 with blotato-api-key: YOUR_API_KEY and Content-Type: application/json. REST nests the source fields. MCP does not.
{
"source": {
"sourceType": "text",
"text": "Our workshop opens on October 15. Registration closes on October 10."
}
}
A 201 response contains the job ID, not extracted content:
{"id": "123e4567-e89b-12d3-a456-426614174000"}
Read GET /v2/source-resolutions-v3/123e4567-e89b-12d3-a456-426614174000 with the same authentication header. A completed response has this shape. The title and content below are illustrative, not guaranteed output text.
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "completed",
"title": "Workshop dates",
"content": "Our workshop opens on October 15. Registration closes on October 10."
}
Completion and recovery
- Wait at least 10 seconds between status requests for an unfinished job. Use a bounded wait, such as 2 minutes, then report the saved ID and pending state. This is a client wait budget, not a service completion promise.
- On
completed, use the returnedcontentandtitle. Do not treat an accepted ID as extracted content. If MCP content ends with[output truncated], it is not the full extraction. Use the REST lookup with the same ID when your client has an authorized API connection, or disclose the incomplete content. Repeated MCP lookups do not paginate the text. - On REST or MCP status lookup
failed, inspectmessage. The MCP create tool reports extraction failure throughisErrorwith the source ID, while the status tool returns afailedstatus in its JSON result. Check both the tool error flag and the operation status. Correct the source or access problem before another extraction attempt. - After a timeout, look up the saved ID instead of submitting another extraction. If no ID was received, report the uncertain outcome before retrying.
- Adapt the content to the user's request. Stop after returning the content for an extraction-only request. For publication, use existing media, or omit media for text-only posts supported by the selected platform. Create a visual only when new media is requested. Follow Publish and verify with the user's publication approval.
Extraction produces source content. It does not itself download a reusable social video or publish a post. An Instagram caption without an image or video is insufficient for publishing.
See Create Source and Get Source for source-specific requirements and errors.
Read post analytics
Prompt for your assistant:
Compare my posts for the period I specify. Use Blotato's returned metrics and snapshot dates. Identify missing metrics and explain refresh timing before drawing conclusions.
Select the posts
Use an authenticated connection. Resolve the user's date range and timezone before requesting a ranking. since and until filter publication dates, not the dates on which engagement occurred. These results are not a daily engagement breakdown.
Call blotato_list_top_posts with a supported ranking metric. This example requests up to 10 Instagram posts published in the specified UTC interval:
{
"platform": "instagram",
"since": "2026-09-01T00:00:00Z",
"until": "2026-09-08T00:00:00Z",
"sortBy": "views_count",
"limit": 10
}
For REST, request GET https://backend.blotato.com/v2/analytics with these fields as URL-encoded query parameters and blotato-api-key: YOUR_API_KEY. Read items from the result. An empty list does not establish 0 engagement. Check date filters, platform coverage, and plan access.
Inspect a post
Use blotato_list_posts to locate a specific post, or select a published post from the ranking. Call blotato_get_post_analytics with its published post ID:
{"id": "123e4567-e89b-12d3-a456-426614174000"}
For REST, request GET /v2/posts/123e4567-e89b-12d3-a456-426614174000/analytics with the authentication header. This id is not postSubmissionId.
Read metrics, lastFetchedAt, lastError, and history. Each history entry has fetchedAt and metrics. Metric counts are returned as strings. Response metric names such as viewsCount differ from ranking keys such as views_count. Preserve numeric precision when comparing large counts.
Completion and missing data
- Report the returned metric values and snapshot times. Different collection times affect comparisons.
- Treat missing or null metrics as unavailable, not 0. If the response is an error, preserve its message instead of manufacturing an empty result.
- For
404, distinguish a missing published post, unavailable plan access, and analytics not yet synced using the returned error. Do not retry post creation to obtain analytics. - Check the post's platform, eligibility, and publication time against refresh checkpoints. Reading analytics returns stored snapshots. It does not trigger collection.
- Stop after reporting the available evidence and next checkpoint or unresolved error. Repeated immediate reads do not force a refresh. A new connection does not promise historical backfill. Follow pending-data diagnosis before recommending reconnection.
Read the API reference and metrics reference before promising a metric or refresh interval. Platform, plan, and interface coverage differ.
Read and reply to comments
Blotato's comments API and MCP tools support Instagram and Facebook.
Prompt for your assistant:
Find comments on the posts I select, summarize them, and draft replies. When I ask you to send a reply, post it and verify its final status.
Find the post and comment
- Use an authenticated connection and an Instagram or Facebook account with comments enabled and the required permissions.
- Call
blotato_list_poststo find the selected published post's Blotato ID. - Call
blotato_list_commentswith the following shape. Replace the examplepostIdwith the returned ID.
{"postId": "123e4567-e89b-12d3-a456-426614174000", "limit": 50}
- Read
items. If acursoris returned and more results are needed, pass it with the same filters in the next call. A missing cursor marks the end. - Select the intended comment. A reply's parent must be a top-level comment with
status: "posted"on the same post. Replies to replies are not supported.
Send an approved reply
Call blotato_post_comment once with the user's approved text and IDs from the lookup:
{
"postId": "123e4567-e89b-12d3-a456-426614174000",
"parentCommentId": "123e4567-e89b-12d3-a456-426614174001",
"text": "Thanks for your question. Registration closes on October 10."
}
Omit parentCommentId only when the user requested a new top-level comment. Do not omit it to bypass a reply error.
Save the returned comment id. Call blotato_get_comment with:
{"commentId": "123e4567-e89b-12d3-a456-426614174002"}
For REST, use GET https://backend.blotato.com/v2/comments?postId=PUBLISHED_POST_ID&limit=50, POST /v2/comments with the same reply JSON, and GET /v2/comments/RETURNED_COMMENT_ID. Include blotato-api-key: YOUR_API_KEY on every request and Content-Type: application/json on POST. URL-encode query values.
Completion and recovery
| Returned status | Next action |
|---|---|
posted | Report the reply as posted. |
queued or processing | Read the same comment again. Do not send another reply. |
failed | Stop and inspect errorCode and errorMessage. |
deleted | Report the deleted state. Do not replace the comment without the user's request. |
Use a client polling budget, such as 10-second intervals for up to 2 minutes. This is not a delivery-time guarantee. If still pending, retain the ID and report the pending state. After a send timeout with no ID, inspect recent comments before considering another write. If the outcome remains uncertain, stop rather than risk a duplicate reply.
Read Comments for plan access, retention, and platform restrictions.
An empty inbox after connecting is a sync question. Follow Inbox setup and timing before concluding the account has no comments.
Read and reply to messages
Blotato's messaging API and MCP tools support Instagram and Facebook. Replies are subject to the platform's messaging rules and windows.
Prompt for your assistant:
Find the conversation I specify, read its recent messages, and draft a reply. When I ask you to send it, use the existing recipient identifiers and verify the send status.
Find the recipient
- Use an authenticated connection and confirm messaging permissions and the platform messaging window.
- Call
blotato_list_conversations, filtering by the intended account and platform. Select the conversation fromitems. Follow returned cursors until the requested conversation is found or the results end.
{"accountId": "98434", "platform": "instagram", "limit": 50}
- Call
blotato_list_messageswith the selected conversation'sid. Replace all example IDs with returned values.
{"conversationId": "cnv_abc123", "limit": 50}
- Read
directionbefore selecting the reply recipient. For anincomingmessage, the other participant issenderId. For anoutgoingmessage, the other participant isrecipientId. Use the conversation'saccountIdas the sending Blotato account. Do not invent a recipient ID from a username or send to the connected account itself.
Send an approved reply
For this Instagram example, assume the selected incoming message's senderId is 1784000000. After the user approves the reply, call blotato_send_message once:
{
"accountId": "98434",
"platform": "instagram",
"recipientId": "1784000000",
"text": "Thanks for asking. Registration closes on October 10."
}
For REST, send the following JSON to POST https://backend.blotato.com/v2/messages with blotato-api-key: YOUR_API_KEY and Content-Type: application/json. REST uses target, not MCP's top-level platform.
{
"accountId": "98434",
"recipientId": "1784000000",
"text": "Thanks for asking. Registration closes on October 10.",
"target": {"targetType": "instagram"}
}
For Facebook, select the Page from account lookup and supply MCP pageId or REST target.pageId with the Facebook platform value. Do not reuse the Instagram target or select the first Page without matching the user's request.
REST lookups use GET /v2/conversations?accountId=ACCOUNT_ID&platform=instagram&limit=50 and GET /v2/messages?conversationId=CONVERSATION_ID&limit=50. Use the authentication header and URL-encode query values.
Verify the send
Save the returned message id. The initial queued state is not confirmation of delivery. Call blotato_get_message with:
{"messageId": "msg_abc123"}
For REST, read GET /v2/messages/RETURNED_MESSAGE_ID with the authentication header.
- On outgoing
sent, report the message as sent. This does not establish the recipient read it. - On
failed, stop and preserveerrorCodeanderrorMessage. Resolve permissions, messaging-window, recipient, or account errors before another attempt. - For
queuedorprocessing, read the same ID within a bounded client wait, such as 10-second intervals for up to 2 minutes. If still pending, report the saved ID and state. This budget is not a delivery promise. - After a send timeout, inspect the saved message or recent conversation messages. Do not resend while the first attempt's outcome remains uncertain.
For buttons, quick replies, and comment-to-DM behavior, read the Messages reference before choosing a message shape. For connection and history questions, see Inbox setup.
Manage DM automations
Use DM automations for supported Instagram and Facebook comment or message triggers. Read the DM Automations guide for trigger behavior, limits, gates, and platform restrictions.
Prompt for your assistant:
Set up a Blotato DM automation for the account, trigger, and reply I describe. Review the trigger and reply with me, then apply my requested activation state. Show how I will check its runs and errors.
- Call
blotato_list_accountsto identify the account. - Call
blotato_list_automationsto inspect existing flows before creating a duplicate. - Read the automation schema and match the trigger and message to the user's request.
- Call
blotato_create_automationorblotato_update_automationfor the requested flow. - Inspect the returned flow and activation state.
- Use
blotato_list_automation_runs,blotato_list_automation_logs, andblotato_get_automation_analyticsto inspect results.
Create an inactive Instagram example
Use an authenticated connection and the account ID from lookup. This example responds to incoming messages matching the keyword workshop. It does not schedule social posts or generate content on a timer.
Call blotato_create_automation after checking existing automations and confirming the trigger and reply with the user:
{
"accountId": "98434",
"platform": "instagram",
"name": "Workshop message reply",
"triggers": [{"type": "message-received", "keywords": ["workshop"], "isActive": true}],
"dmMessage": "Registration closes on October 10.",
"buttons": [],
"isActive": false
}
The trigger is enabled within the draft, but the flow remains inactive because isActive at the top level is false. Read automation.id, automation.isActive, and automation.triggers from the MCP result. Creating a draft is not activation.
For REST, send this JSON to POST https://backend.blotato.com/v2/dm-automations with blotato-api-key: YOUR_API_KEY and Content-Type: application/json:
{
"accountId": "98434",
"platform": "instagram",
"target": {"targetType": "instagram"},
"name": "Workshop message reply",
"triggers": [{"type": "message-received", "keywords": ["workshop"], "isActive": true}],
"dmMessage": "Registration closes on October 10.",
"buttons": [],
"isActive": false
}
The REST result wraps the saved record in flow, not MCP's automation. Save flow.id. Read it later with GET /v2/dm-automations/RETURNED_FLOW_ID and the authentication header. For Facebook, set the Facebook platform and target and include the selected Page ID. See the automation schema.
Activate and verify
If the user requests activation, call blotato_update_automation with the saved flow ID:
{"automationId": "flow_abc123", "isActive": true}
For REST, send this body to PATCH /v2/dm-automations/RETURNED_FLOW_ID. REST requires the patch wrapper, unlike the MCP tool arguments:
{"patch": {"isActive": true}}
Verify the returned activation state. Changes to an already active flow take effect immediately. Do not treat a content update to a live flow as an unpublished draft.
For an authorized test, send the matching message from a different account. Messages sent by the connected account do not start the run. Read the resulting runs with:
{"automationId": "flow_abc123", "limit": 20}
For REST, use GET /v2/dm-automations/RETURNED_FLOW_ID/runs?limit=20. Inspect a selected run's logs with blotato_list_automation_logs or GET /v2/dm-automations/RETURNED_FLOW_ID/logs?flowRunId=RUN_ID. A completed test run verifies the tested trigger, not every future event. If no run appears, check account ownership, activation, and trigger matching before creating another flow. Preserve the flow ID and returned error if a write outcome is uncertain.
Later changes
For one trigger's on/off state, use blotato_update_automation_trigger with current flow and trigger IDs. At least one trigger must stay active while the flow is live. Updating flow content or triggers reissues trigger IDs, so read the response before a later trigger update.
For REST, use the DM Automations API. Trigger updates, flow updates, and archive operations have distinct schemas. Sending a test DM or creating a flow does not prove a real trigger run succeeded. Verify runs and logs.
Check or add credits
Prompt for your assistant:
Check my Blotato credit balance and account email. If I need more credits, tell me where to add them.
- Call
blotato_get_creditsto read the balance, account email, pricing, and purchase limits. - State the returned account email before directing the user to purchase credits. Credits belong to the account and are non-transferable.
- Direct the user to Settings > Billing.
- Recheck the balance after payment when requested.
Request and result
Call blotato_get_credits without arguments, or request GET https://backend.blotato.com/v2/credits with blotato-api-key: YOUR_API_KEY. Read creditsRemaining, accountEmail, purchaseQuantityRange, and pricePer1000CreditsUsd from the response. Do not substitute another plan's monthly allocation for the current balance.
The MCP server does not list a credit-purchase tool. Do not invent a checkout link. After the user finishes payment in Billing, read the balance again when requested and preserve any payment error for billing support.
See Credits reference for balance, pricing, and REST checkout fields.
REST API quickstart
Use this path for HTTP requests, n8n, or Make. To give instructions to Claude, Codex, or another assistant, start with MCP setup.
For step-by-step setup, open the API setup wizard. Choose your tool, then connect a social account, connect the tool, check the connection, and publish a test post.
Your first verified result is an account-list response. Publishing comes after account selection and platform checks.
Get Started with Blotato API
The Blotato API allows you to:
- publish and schedule posts directly to social media platforms
- supports text, image, videos, reels, slideshows, carousels, threads, and stories
- create images, videos, slideshows, and carousels programmatically via templates
It is limited to paying subscribers in order to reduce spam and service abuse, keeping Blotato's integration in good standing with the social platforms.
Plans That Include API
| Plan | API Access |
|---|---|
| Free Trial | No |
| Starter | Yes |
| Creator | Yes |
| Agency | Yes |
API access is included on every paid plan. Generating an API key from Settings > API immediately ends a free trial and activates your paid Starter subscription.
Base URLs
Blotato has two base URLs. Use the one that matches your integration:
| Integration | Base URL |
|---|---|
| REST API (direct HTTP, n8n, Make) | https://backend.blotato.com/v2 |
| MCP Server (ChatGPT, Claude Code, Claude Cowork, Claude Desktop, Cursor, Antigravity, Hermes, OpenClaw) | https://mcp.blotato.com/mcp |
api.blotato.com is not a valid base URL. If your AI tool reports a DNS error for api.blotato.com, it guessed wrong. Use one of the two URLs above.
1. Get Your API Key
:exclamation:IMPORTANT: this will end your free trial immediately and start your paid subscription.
Go to Settings > API and click "Generate API Key".
2. Connect Social Accounts
Go to Accounts and connect your social accounts. If you get stuck, more information here:
3. Verify access
Ask your agent or HTTP client to send this request with your API key:
GET /v2/users/me/accounts HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
A successful response contains items. An empty items array confirms access but means no social accounts are connected. Use each account's returned id as accountId.
Next, follow Publish and verify a post, or choose another agent workflow. Use Accounts and identifiers for Page, board, and playlist IDs.
Optional: install the Blotato integration
n8n
- Follow the Blotato node installation guide for n8n Cloud or self-hosted n8n.
- Configure and verify the credential.
- Use the first-post workflow after selecting the intended account.
Make
- Open any scenario in Make
- Click the "+" icon to add a module
- Search for "Blotato"
- Select the Blotato module
Choose an automation tutorial
New to building automations? Start here:
- Build Your First AI Automation - Build an n8n source-to-visual-to-post workflow with completion checks.
Choose your preferred integration path:
- MCP Server - control Blotato from ChatGPT, Claude.ai, Claude Desktop, Claude Code, Cursor, and more with natural language
- n8n - post everywhere
- Make - post everywhere
- REST API - OpenAPI reference and Examples Below
Blotato has official Make.com and n8n nodes. Zapier does not have an official Blotato app. In Zapier, use Webhooks by Zapier to send authenticated HTTP requests to the Blotato API.
Check out more workflow automation templates here:
Troubleshoot errors
Use the Logs and click on each request to see full payload, response, and error message:
Logs (for debugging): https://my.blotato.com/logs
FIX MY AUTOMATION (n8n only): On a failed n8n request in the Logs, click the green FIX MY AUTOMATION button and Blotato AI will attempt to fix your n8n workflow automatically. This feature is for n8n only -- it does not work for Make, Claude, MCP, or direct REST API calls. Full walkthrough: Fix My Automation.
Raw REST API Calls - Examples
Authentication
To authenticate API requests, include your Blotato API key in the request headers.
Authentication Header
blotato-api-key: YOUR_API_KEY
Requests without a valid API key will be rejected and 401 error will be returned.
Your API key sometimes ends with one or more = characters. Copy the full value, including these characters. Use the quoting required by your client or configuration format. For a 401, follow authentication checks.
Step 0: Get Your Account IDs
Before publishing, fetch your connected accounts to get the accountId:
GET https://backend.blotato.com/v2/users/me/accounts HTTP/1.1
blotato-api-key: YOUR_API_KEY
Use the id from the response as your accountId. For Facebook and LinkedIn, also fetch subaccounts to get pageId. See Accounts reference for details.
Post to a Platform Immediately
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Hello, world!",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
After submission, save postSubmissionId and poll GET /v2/posts/:postSubmissionId until published or failed. A 201 create response confirms acceptance. Follow the completion rules before reporting success.
Post at a Scheduled Time
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Scheduled post example",
"mediaUrls": [],
"platform": "facebook"
},
"target": {
"targetType": "facebook",
"pageId": "987654321"
}
},
"scheduledTime": "2030-06-15T15:00:00Z"
}
Replace the example date with the user's intended future time in UTC. To use the next available calendar slot, replace scheduledTime with useNextFreeSlot: true. Both are top-level fields, outside post. See Scheduling.
Post a Twitter Thread with Multiple Posts
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "This is the first tweet in the thread.",
"mediaUrls": [],
"platform": "twitter",
"additionalPosts": [
{
"text": "Here's the second tweet, adding more info.",
"mediaUrls": []
},
{
"text": "And here's the third tweet to conclude!",
"mediaUrls": []
}
]
},
"target": {
"targetType": "twitter"
}
}
}
Attach Media to Post (images and videos)
Pass any publicly accessible image/video URL into the mediaUrls parameter. No upload step required. Blotato handles the media transfer.
For local files without a public URL, use the Presigned Upload endpoint to upload directly to Blotato. No Google Drive or S3 needed.
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Check out this image!",
"mediaUrls": [
"https://example.com/image.jpg"
],
"platform": "instagram"
},
"target": {
"targetType": "instagram"
}
}
}
The optional Upload Media endpoint is still available if you need to host media on Blotato's servers. See Upload Media.
For AI Agents
If you are an AI agent or LLM integration, start with the plain-text API reference:
This index links to references by task, including request examples, status values, and workflow instructions.
For async workflow patterns and code examples, see Protocol and Recipes.
For the full endpoint reference, see API Reference.
Public API operation index
This index covers Blotato's public operations in the OpenAPI document. Use the linked reference for parameters and responses.
Base URL: https://backend.blotato.com. The paths below include /v2. Authenticate with blotato-api-key.
| Method | Path | Reference |
|---|---|---|
| GET | /v2/dm-automations | List automations |
| POST | /v2/dm-automations | Create automation |
| GET | /v2/dm-automations/{id} | Get automation |
| PATCH | /v2/dm-automations/{id} | Update automation |
| DELETE | /v2/dm-automations/{id} | Archive automation |
| GET | /v2/dm-automations/{id}/runs | List automation runs |
| GET | /v2/dm-automations/{id}/logs | List automation logs |
| GET | /v2/dm-automations/{id}/analytics | Get automation analytics |
| PATCH | /v2/dm-automations/{flowId}/triggers/{triggerId} | Update trigger |
| GET | /v2/comments | List comments |
| POST | /v2/comments | Post comment |
| GET | /v2/comments/{commentId} | Get comment |
| GET | /v2/credits | Get credits |
| POST | /v2/credits | Buy credits |
| POST | /v2/media | Upload URL |
| POST | /v2/media/uploads | Upload local file |
| GET | /v2/conversations | List conversations |
| GET | /v2/conversations/{conversationId} | Get conversation |
| GET | /v2/messages | List messages |
| POST | /v2/messages | Send message |
| GET | /v2/messages/{messageId} | Get message |
| GET | /v2/integrations/oauth2/linkedin/pages | Find LinkedIn pages |
| GET | /v2/social/pinterest/boards | List Pinterest boards |
| GET | /v2/posts | List posts |
| POST | /v2/posts | Create post |
| GET | /v2/posts/{postSubmissionId} | Get submission status |
| GET | /v2/posts/{id}/analytics | Get post analytics |
| GET | /v2/analytics | Rank posts |
| GET | /v2/analytics/platforms | Compare platforms |
| GET | /v2/analytics/summary | Get analytics summary |
| GET | /v2/published-posts | Search published posts |
| GET | /v2/published-posts/{id} | Get a published post |
| GET | /v2/schedules | List scheduled posts |
| GET | /v2/schedules/{id} | Get scheduled post |
| PATCH | /v2/schedules/{id} | Update scheduled post |
| DELETE | /v2/schedules/{id} | Delete scheduled post |
| POST | /v2/source-resolutions-v3 | Extract source |
| GET | /v2/source-resolutions-v3/{id} | Get source status |
| GET | /v2/users/me | Get user |
| GET | /v2/users/me/usage | Get usage |
| GET | /v2/users/me/accounts | List accounts |
| GET | /v2/users/me/accounts/{accountId}/subaccounts | List subaccounts |
| DELETE | /v2/videos/{id} | Delete visual |
| GET | /v2/videos/creations/{id} | Get visual status |
| POST | /v2/videos/from-templates | Create visual |
| GET | /v2/videos/templates | List templates |
Additional documented routes
Account usage and schedule-slot management are implemented and documented separately, but are absent from this OpenAPI export. Their absence here does not mean the features are unavailable.
For first-time setup, use the REST quickstart. For tool calls, use the MCP tool catalog. The MCP catalog is not a generated copy of every REST operation.
Users
General
Use these endpoints to verify your API key and check account usage.
Endpoints
GET /v2/users/me
Fetches the current user's information, including subscription status and plan. This endpoint is useful for verifying that your API key is valid and referencing your own userId.
Response Keys
| Name | Type | Description |
|---|---|---|
id | string | The unique ID of the user. |
subscriptionStatus | string | The user's subscription status (e.g., active, generic_pro). |
subscriptionPlan | string | The user's plan tier: starter, creator, or agency. |
apiKey | string | [Sensitive] The user's API key. |
Examples
Get verification info
GET https://backend.blotato.com/v2/users/me HTTP/1.1
blotato-api-key: blt_...
Response 200 OK
{
"id": "e931cdad-0c31-4191-8930-745a76c8e31a",
"subscriptionStatus": "active",
"subscriptionPlan": "creator",
"apiKey": "blt_..."
}
GET /v2/users/me/usage
Returns the current user's connected-account usage, active-contact usage, and active-contact limit.
Use this endpoint before connecting more accounts or sending messages at scale so you know how close you are to your plan limits. For the limit values on each plan, see Plan Limits.
Response Keys
| Name | Type | Description |
|---|---|---|
accounts | integer | Number of connected channels counting toward the connected-accounts limit. Facebook Pages count. The Facebook login itself does not count. LinkedIn profiles and LinkedIn company Pages count. |
contacts | integer | Number of contacts messaged this month, counting toward the active-contacts limit. |
contactsLimit | integer or "unlimited" | Maximum active contacts you can message this month. This matches your current account limit, including any custom active-contact limit on your account. |
Get usage
GET https://backend.blotato.com/v2/users/me/usage HTTP/1.1
blotato-api-key: blt_...
Response 200 OK
{
"accounts": 12,
"contacts": 438,
"contactsLimit": 6000
}
Accounts
List Connected Accounts
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /users/me/accounts
Method: GET
Description
Returns all social media accounts connected to your Blotato account. Use this to get the accountId required for publishing posts.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | No | Filter by platform. Values: twitter, instagram, linkedin, facebook, tiktok, pinterest, threads, bluesky, youtube |
The platform values here are the same values used in content.platform and target.targetType when publishing.
Response
Status Code: 200 OK
{
"items": [
{
"id": "98432",
"platform": "twitter",
"fullname": "Jane Smith",
"username": "janesmith"
},
{
"id": "98433",
"platform": "facebook",
"fullname": "Jane Smith",
"username": "janesmith"
}
]
}
| Field | Type | Description |
|---|---|---|
items | array | List of connected accounts |
items[].id | string | Account ID. Use this as accountId when publishing. |
items[].platform | string | Platform type (e.g., twitter, facebook, instagram) |
items[].fullname | string | Display name of the account |
items[].username | string | Username or handle |
If no accounts are returned, the user needs to connect social accounts in Accounts.
Examples
List all accounts
GET https://backend.blotato.com/v2/users/me/accounts HTTP/1.1
blotato-api-key: YOUR_API_KEY
Filter by platform
GET https://backend.blotato.com/v2/users/me/accounts?platform=instagram HTTP/1.1
blotato-api-key: YOUR_API_KEY
List Subaccounts (Pages)
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /users/me/accounts/:accountId/subaccounts
Method: GET
Description
Returns subaccounts for a connected account. Subaccounts include Facebook Pages, LinkedIn Company Pages, and YouTube Playlists. Use this to get the pageId required for publishing to Facebook/LinkedIn, or playlistIds for adding YouTube videos to playlists.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | The account ID from the List Accounts endpoint |
Response
Status Code: 200 OK
{
"items": [
{
"id": "123456789",
"accountId": "98433",
"name": "My Business Page"
}
]
}
| Field | Type | Description |
|---|---|---|
items | array | List of subaccounts |
items[].id | string | Subaccount ID. Use this as target.pageId when publishing to Facebook or LinkedIn. |
items[].accountId | string | Parent account ID |
items[].name | string | Name of the page |
If subaccounts is empty, the user needs to connect a Facebook Page, LinkedIn Company Page, or YouTube account in Accounts.
Example
GET https://backend.blotato.com/v2/users/me/accounts/98433/subaccounts HTTP/1.1
blotato-api-key: YOUR_API_KEY
List Available LinkedIn Pages
Use GET /v2/integrations/oauth2/linkedin/pages?accountId=ACCOUNT_ID to list organization pages the connected LinkedIn account administers. accountId is required and comes from List Connected Accounts.
The response contains items, each with id, name, and isActive. isActive: true means Blotato is already connected to the page. This endpoint discovers available pages. For publishing, retrieve connected page IDs through List Subaccounts above.
GET https://backend.blotato.com/v2/integrations/oauth2/linkedin/pages?accountId=98434 HTTP/1.1
blotato-api-key: YOUR_API_KEY
Connect missing pages in Accounts, then repeat the subaccounts lookup. A 422 response for an expired connection requires reconnection. The route limit is 20 requests per minute.
How to Get the Right IDs for Publishing
Different platforms need different IDs. Here is how to get them for each platform.
Twitter, Instagram, TikTok, Threads, Bluesky
These platforms need only an accountId:
- Call
GET /v2/users/me/accounts?platform=twitter(replace with your platform) - Use
items[].idasaccountIdin your publish request - If multiple accounts are returned, use
fullnameorusernameto identify the correct one, or ask the user which account to use
YouTube
YouTube needs an accountId. To add videos to playlists, also fetch subaccounts to get playlist IDs:
- Call
GET /v2/users/me/accounts?platform=youtube - Use
items[].idasaccountId - Call
GET /v2/users/me/accounts/{accountId}/subaccounts - Use
items[].idvalues astarget.playlistIdsin your publish request playlistIdsis optional -- omit it to publish without adding to a playlist
Facebook requires both accountId and pageId:
- Call
GET /v2/users/me/accounts?platform=facebook - Use
items[].idasaccountId - Call
GET /v2/users/me/accounts/{accountId}/subaccounts - Use
items[].idastarget.pageIdin your publish request - If multiple pages are returned, use
nameto identify the correct one, or ask the user which page to use
Full example:
1. GET /v2/users/me/accounts?platform=facebook
Response: { "items": [{ "id": "98433", "platform": "facebook", ... }] }
2. GET /v2/users/me/accounts/98433/subaccounts
Response: { "items": [{ "id": "123456789", "name": "My Business Page" }] }
3. POST /v2/posts with:
{
"post": {
"accountId": "98433",
"content": { "text": "Hello!", "mediaUrls": [], "platform": "facebook" },
"target": { "targetType": "facebook", "pageId": "123456789" }
}
}
LinkedIn Company Page
To post to a LinkedIn Company Page instead of your personal profile:
- Call
GET /v2/users/me/accounts?platform=linkedin - Use
items[].idasaccountId - Call
GET /v2/users/me/accounts/{accountId}/subaccounts - Use
items[].idastarget.pageId - If you skip
pageId, the post goes to your personal LinkedIn profile
Pinterest requires a boardId. Fetch boards with the List Pinterest Boards endpoint:
- Call
GET /v2/users/me/accounts?platform=pinterest - Use
items[].idasaccountId - Call
GET /v2/social/pinterest/boards?accountId={accountId} - Use
items[].idastarget.boardIdin your publish request - If multiple boards are returned, use
nameto identify the correct one, or ask the user which board to use
Web app shortcut: you can also grab a Board ID without the API. Go to Accounts, scroll to your Pinterest account, and select a Board -- Blotato copies its Board ID to your clipboard. Use this if the boards endpoint returns an empty list.
Full example:
1. GET /v2/users/me/accounts?platform=pinterest
Response: { "items": [{ "id": "98436", "platform": "pinterest", ... }] }
2. GET /v2/social/pinterest/boards?accountId=98436
Response: { "items": [{ "id": "1234567890123456789", "name": "Summer Outfits" }] }
3. POST /v2/posts with:
{
"post": {
"accountId": "98436",
"content": { "text": "Check out this pin!", "mediaUrls": ["https://example.com/image.jpg"], "platform": "pinterest" },
"target": { "targetType": "pinterest", "boardId": "1234567890123456789" }
}
}
List Pinterest Boards
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /social/pinterest/boards
Method: GET
Description
Returns boards owned by a connected Pinterest account. Use this to get the boardId required when publishing a pin.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | Blotato Pinterest account ID from GET /users/me/accounts. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "1234567890123456789",
"name": "Summer Outfits"
}
]
}
| Field | Type | Description |
|---|---|---|
items | array | List of Pinterest boards (max 250) |
items[].id | string | Board ID. Use this as target.boardId when publishing a pin. |
items[].name | string | Display name of the board on Pinterest |
Example
GET https://backend.blotato.com/v2/social/pinterest/boards?accountId=98436 HTTP/1.1
blotato-api-key: YOUR_API_KEY
Credits /v2/credits
Blotato credits pay for AI generations such as videos and images. Use these endpoints to check your remaining credit balance, see current pricing, and buy more credits. Two endpoints:
- Get Credit Balance —
GET /v2/credits - Buy Credits —
POST /v2/credits
Credits belong to a single account and are non-transferable. Confirm the account email from Get Credit Balance before you buy, so the credits land on the account you intend.
Get Credit Balance
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /credits
Method: GET
Description
Returns your remaining credits, the email of the account the API key belongs to, and current purchase pricing.
Response
Status Code: 200 OK
| Field | Type | Description |
|---|---|---|
creditsRemaining | integer | Credits left on the account. |
accountEmail | string | Email of the account the API key belongs to. |
purchaseQuantityRange | object | Allowed purchase range, with min and max credits per purchase. |
pricePer1000CreditsUsd | number | Price in US dollars per 1,000 credits. |
Example response:
{
"creditsRemaining": 54688,
"accountEmail": "user@example.com",
"purchaseQuantityRange": { "min": 1000, "max": 10000 },
"pricePer1000CreditsUsd": 6.0
}
Errors
| Status | Reason |
|---|---|
401 | Missing or invalid API key. |
500 | Server error. |
Buy Credits
Endpoint
URL: /credits
Method: POST
Description
Creates a Stripe Checkout link to buy credits. Creating the link does not charge anything. The account owner opens the link in a browser and completes payment there, and the purchased credits land on this account. Stripe creates an invoice for the credit purchase after checkout succeeds. Buy between 1,000 and 10,000 credits per request.
Confirm the account email from Get Credit Balance first, since credits are non-transferable between accounts.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
quantity | integer | Yes | Credits to buy. Between 1,000 and 10,000. |
referral | string | No | Optional referral code. |
Response
Status Code: 201 Created
| Field | Type | Description |
|---|---|---|
checkoutUrl | string | Stripe Checkout URL. Open it in a browser to complete payment. No charge happens until checkout completes. |
Example response:
{
"checkoutUrl": "https://checkout.stripe.com/c/pay/cs_test_123"
}
Errors
| Status | Reason |
|---|---|
400 | The quantity is outside the 1,000 to 10,000 range, or the request body is invalid. |
401 | Missing or invalid API key. |
429 | Rate limit exceeded (10 requests per hour). |
500 | Server error. |
Pricing
Credits cost $6.00 per 1,000 credits. Read the current price from Get Credit Balance (pricePer1000CreditsUsd), since pricing changes over time.
Upload Media /v2/media
Upload is Now Optional
You no longer need to upload media to Blotato before publishing. You can pass any publicly accessible image/video URL directly into the mediaUrls parameter in the Publish node. Blotato handles the media transfer automatically.
For local files without a public URL, use the Presigned Upload endpoint below. This lets you upload directly to Blotato without needing Google Drive, S3, or any other intermediate storage. Upload size depends on your plan (see Plan Limits).
The legacy Upload Media endpoint is still available if you prefer to use it, or if you need to host media on Blotato's servers.
Upload Media
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /media
Method: POST
Description
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 subject to your plan's upload size limit. See Plan Limits for more details.
If you are using the n8n "Binary Data" upload option, the file size limit is 15MB. For larger files, use the Presigned Upload endpoint above (no external hosting needed), or host your media on Google Drive, AWS S3, or another cloud storage service and pass the URL instead.
Request
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | ✅ | The URL of the media to upload. |
Responses
Success Response
Status Code: 201 Created
Response Body:
{
"url": "https://database.blotato.io/path-to-uploaded-media.jpg"
}
Error Responses
Internal Server Error
Status Code: 500 Internal Server Error
{
"code": 9999,
"message": "An unknown error occurred."
}
Too Many Requests
Media upload has a user-level rate limit of 30 requests / minute.
Status Code: 429 Too many requests
{
"statusCode": 429,
"message": "Rate limit exceeded, retry in 49 seconds"
}
Error Codes
The following client error codes may be returned:
| Code | Description |
|---|---|
90009 | Blotato could not fetch the media URL. Confirm the URL loads or downloads without signing in, then try again. |
9999 | Unknown error. |
Examples
1. Upload Media
POST https://backend.blotato.com/v2/media HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"url": "https://example.com/image.jpg"
}
Response:
{
"url": "https://database.blotato.io/d1655c49-0bc4-4dd0-88b2-323ce0069fa4.jpg"
}
Presigned Upload (Local Files)
Upload local files directly to Blotato without hosting them on Google Drive or S3 first. This is the recommended approach for MCP users and anyone working with local files.
Endpoint
URL: /media/uploads
Method: POST
Rate limit: 120 requests per minute
Request
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Filename with extension (e.g., "photo.jpg", "video.mp4"). Used to determine content type. |
Response
Status Code: 201 Created
{
"presignedUrl": "https://...",
"publicUrl": "https://..."
}
presignedUrl-- upload your file here via HTTP PUT. Expires after a short period.publicUrl-- the final public URL to use inmediaUrlswhen publishing.
Complete Example: Upload a Local File and Post It
Three steps: get the presigned URL, upload the file, then publish the post.
Step 1: Get a presigned upload URL
curl -X POST https://backend.blotato.com/v2/media/uploads \
-H "Content-Type: application/json" \
-H "blotato-api-key: YOUR_API_KEY" \
-d '{"filename": "product-photo.jpg"}'
Response:
{
"presignedUrl": "https://database.blotato.io/storage/v1/object/upload/sign/...",
"publicUrl": "https://database.blotato.io/storage/v1/object/public/.../product-photo.jpg"
}
Step 2: Upload the file to the presigned URL
curl -X PUT "PRESIGNED_URL_FROM_STEP_1" \
-H "Content-Type: image/jpeg" \
--data-binary @product-photo.jpg
Use the correct Content-Type for your file (image/jpeg, image/png, video/mp4, etc.).
Step 3: Publish a post using the public URL
curl -X POST https://backend.blotato.com/v2/posts \
-H "Content-Type: application/json" \
-H "blotato-api-key: YOUR_API_KEY" \
-d '{
"post": {
"accountId": "YOUR_ACCOUNT_ID",
"content": {
"text": "Check out this product!",
"mediaUrls": ["PUBLIC_URL_FROM_STEP_1"],
"platform": "instagram"
},
"target": { "targetType": "instagram" }
}
}'
Max file size depends on your plan. See: Plan Limits for more details. The presigned URL expires after a short period -- upload the file immediately after receiving it.
Troubleshooting: presigned PUT fails in Claude Cowork or Claude Desktop
If POST /v2/media/uploads returns a presignedUrl but the PUT step to that URL fails with a sandbox, proxy, network egress, or "Stream closed" error, this is a Claude Cowork / Claude Desktop sandbox restriction, not a Blotato API issue.
Fix it by allowlisting database.blotato.io in Cowork's network egress settings. Full steps: Presigned upload PUT fails / "Sandbox error" / network egress blocked.
For Claude Code (sandbox not user-configurable), skip the local upload entirely and pass a public URL into mediaUrls directly.
Using Google Drive as a Media Source
Google Drive share links open a viewer page, not a direct file. Blotato needs a direct file URL to fetch and read media.
Set sharing permissions
For automation workflows (n8n, Make.com), set the entire Google Drive folder to "Anyone with the link" as Viewer. All files inside that folder inherit the same permission, so you do not need to set permissions on each file individually.
For one-off uploads, set the individual file to "Anyone with the link" as Viewer.
Common Google Drive URL Errors
Folder URLs don't work: If your link looks like /drive/folders/..., it's a folder link. Blotato needs a direct link to a specific file, not a folder.
Preview URLs don't work reliably: If your link ends with /view?..., it points to Google Drive's preview page, not the raw file.
Use the direct download URL format
For Google Drive files, including large videos, first replace the standard share link with this format:
https://drive.usercontent.google.com/download?id={FILE_ID}&export=download&confirm=t
Replace {FILE_ID} with the ID from your share link. For example, if your share link is:
https://drive.google.com/file/d/1aBcDeFgHiJkLmNoPqRsTuVwXyZ/view
The file ID is 1aBcDeFgHiJkLmNoPqRsTuVwXyZ, so the direct URL is:
https://drive.usercontent.google.com/download?id=1aBcDeFgHiJkLmNoPqRsTuVwXyZ&export=download&confirm=t
Make sure the file is shared with "Anyone with the link" as Viewer.
The confirm=t parameter requests the file download from Google Drive. Blotato does not impose a 100 MB Google Drive cutoff. The file still must fit your Blotato plan's upload limit and the destination platform's media limit.
Seeing error "Google Drive can't scan this file for viruses"?
Google Drive sometimes returns a virus-scan warning page instead of the file for large videos. Blotato converts Google Drive share links to the direct download format above, but Google Drive might still return the warning page.
If the direct download URL still returns the warning page, use the Presigned Upload flow, frame.io, AWS S3, or Google Cloud Storage. These options avoid the Google Drive warning page.
Publish Post /v2/posts
Publishing a Post
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /posts
Method: POST
Rate Limit: 30 requests / minute
Description
Publish a new post to a social media platform. The request must include the post content, target platform, and an accountId (fetched from GET /v2/users/me/accounts).
After submitting, poll Get Post Status with the returned postSubmissionId to track publishing progress.
Before You Start
- Fetch your connected accounts:
GET /v2/users/me/accounts(docs) - Fetch your subaccounts to get
pageIdfor Facebook/LinkedIn andplaylistIdsfor YouTube:GET /v2/users/me/accounts/{accountId}/subaccounts(docs). - For a social platform, set
content.platformandtarget.targetTypeto the same value (e.g., both"twitter"). The webhook target usesotherandwebhook.
Request Body
The request body has two top-level fields: post (required) and optional scheduling fields. Do not nest scheduling fields inside post.
| Field | Type | Required | Description |
|---|---|---|---|
post | object | Yes | The post content and metadata. |
scheduledTime | string | No | ISO 8601 timestamp with timezone offset for the requested future time. Use this without useNextFreeSlot: true. |
useNextFreeSlot | boolean | No | Schedule at the next available slot time. Defaults to false. Requires an available slot matching the platform, account, and Page. |
Scheduling behavior:
- Choose 1 scheduling method. If
scheduledTimeis set, it supplies the publish time. SettinguseNextFreeSlot: trueas well still runs slot validation and fails when no matching slot is available. Do not combine the fields. - If
useNextFreeSlotistrue(and noscheduledTime): the post is scheduled at the next available calendar slot matching the destination. - If neither
scheduledTimenoruseNextFreeSlotis provided: the post publishes immediately. - Both fields must be root-level (siblings of
post). If they are nested insidepost,options, or any other object, they are ignored and the post publishes immediately.
post Object
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | The account ID from GET /v2/users/me/accounts. |
content | object | Yes | The content of the post. See content below. |
target | object | Yes | The target platform and platform-specific fields. See target below. |
content Object
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The text content of the post. |
mediaUrls | array of strings | Yes | Array of media URLs. Pass any publicly accessible URL -- no upload step required. Pass [] for text-only posts. |
platform | string | Yes | For social platforms, match target.targetType. Use other for the webhook target. Values: twitter, linkedin, facebook, instagram, pinterest, tiktok, threads, bluesky, youtube, other |
additionalPosts | array | No | Additional posts for threads (Twitter, Bluesky, Threads). Each has text and mediaUrls. |
other is reserved for publishing to a custom webhook. It does not represent another native social platform.
target Object
The target object requires targetType and platform-specific fields. Match content.platform for social platforms. For a custom webhook, use content.platform: "other" with target.targetType: "webhook".
Quick Reference: Required Fields Per Platform
| Platform | targetType | Required Fields | Optional Fields |
|---|---|---|---|
"twitter" | (none) | (none) | |
"linkedin" | (none) | pageId | |
"facebook" | pageId | mediaType, link, firstComment | |
"instagram" | (none) | mediaType, altText, collaborators, coverImageUrl, shareToFeed, audioName, trial, firstComment | |
| TikTok | "tiktok" | privacyLevel, disabledComments, disabledDuet, disabledStitch, isBrandedContent, isYourBrand, isAiGenerated | title, autoAddMusic, isDraft, imageCoverIndex, videoCoverTimestamp |
"pinterest" | boardId | title, altText, link | |
| Threads | "threads" | (none) | replyControl |
| Bluesky | "bluesky" | (none) | (none) |
| YouTube | "youtube" | title, privacyStatus, shouldNotifySubscribers | isMadeForKids, containsSyntheticMedia, playlistIds, thumbnailUrl |
| Webhook | "webhook" | url | (none) |
| Field | Type | Required |
|---|---|---|
targetType | "twitter" | Yes |
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "linkedin" | Yes | |
pageId | string | No | LinkedIn Company Page ID from subaccounts. Omit to post to personal profile. |
Carousels: Pass 2-10 image URLs (JPG, PNG) in content.mediaUrls. Blotato auto-builds a LinkedIn Document carousel (LinkedIn's modern PDF-based carousel format — viewers swipe through pages). Videos cannot be mixed into a carousel.
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "facebook" | Yes | |
pageId | string | Yes | Facebook Page ID from subaccounts. |
mediaType | "reel" or "story" | See description | Video posts must use "reel" (regular feed videos no longer supported). Set "story" for Stories. Omit (default) for text-only or image posts. Stories require one video or image attachment; if more than one is provided, only the first is used. See Facebook Reel requirements. |
link | string | No | URL to attach as a link preview. |
firstComment | string | No | Auto-posts this text as the first comment right after the post publishes. Up to 8000 characters. Works on feed posts and reels, not Stories. |
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "instagram" | Yes | |
mediaType | "reel" or "story" | No | Default: "reel" for videos. Set "story" to publish one image or video as an Instagram Story. |
altText | string | No | Alt text for images. Up to 1000 characters. |
collaborators | array of strings | No | Instagram handles to tag (max 3). Do not include the @ sign. Single image posts and reels only - not supported on carousels (multi-media posts), which will fail to publish. |
coverImageUrl | string | No | Cover image URL for reels. Max 8MB. |
shareToFeed | boolean | No | Share the reel to the Instagram feed. Only applies to reels. |
audioName | string | No | Custom audio name for reels. You can only set this once per reel. |
trial | object | No | Settings for trial reels. Trial reels are shown to non-followers first. Only applies to reels. See trial object below. |
firstComment | string | No | Auto-posts this text as the first comment right after the post publishes. Up to 2200 characters. Works on posts, carousels, and reels, not Stories. Useful for putting a link in the first comment. |
Instagram Stories do not support captions through Meta's publishing API. Set the required content.text field to an empty string for a Story. To display text, render it into the image or video before publishing. Native Story text, link stickers, and other interactive stickers require manual editing in Instagram. See Instagram limitations.
trial Object
| Field | Type | Required | Description |
|---|---|---|---|
graduationStrategy | string | Yes | "MANUAL" (you promote to followers manually) or "SS_PERFORMANCE" (Instagram auto-promotes based on performance). |
TikTok
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "tiktok" | Yes | |
privacyLevel | string | Yes | SELF_ONLY, PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, or FOLLOWER_OF_CREATOR |
disabledComments | boolean | Yes | |
disabledDuet | boolean | Yes | |
disabledStitch | boolean | Yes | |
isBrandedContent | boolean | Yes | Set true only for a paid partnership with a third-party brand. Adds TikTok's paid-partnership disclosure. Set false for organic content. |
isYourBrand | boolean | Yes | Set true when the post promotes your own brand, product, or business. This drives TikTok's "Promotional content" disclosure. Set false for organic content. |
isAiGenerated | boolean | Yes | Set true when the content is AI-generated. This drives TikTok's AI-generated label. Set false for content you filmed or made yourself. |
title | string | No | Title for image posts. Max 90 characters. No effect on videos. |
autoAddMusic | boolean | No | Add music to photo posts. No effect on videos. Default: false. |
isDraft | boolean | No | Post as a draft. Drafts appear in TikTok mobile app notifications, not the Drafts folder. |
imageCoverIndex | number | No | Index (starting from 0) of image to use as cover for carousels. |
videoCoverTimestamp | number | No | Timestamp in milliseconds to use as video cover. |
For organic content that is not sponsored and not AI-generated, set isBrandedContent, isYourBrand, and isAiGenerated to false. Set isYourBrand to true only to promote your own brand, and isAiGenerated to true only for AI-generated content. Each field maps to a separate TikTok content disclosure, so set only the ones that apply.
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "pinterest" | Yes | |
boardId | string | Yes | Pinterest Board ID. Get from List Pinterest Boards. |
title | string | No | Pin title. |
altText | string | No | Pin alt text. |
link | string | No | Pin URL link. |
Pinterest "description" comes from the content.text field.
Threads
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "threads" | Yes | |
replyControl | string | No | everyone, accounts_you_follow, or mentioned_only |
Bluesky
| Field | Type | Required |
|---|---|---|
targetType | "bluesky" | Yes |
YouTube
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "youtube" | Yes | |
title | string | Yes | Video title. |
privacyStatus | string | Yes | private, public, or unlisted |
shouldNotifySubscribers | boolean | Yes | |
isMadeForKids | boolean | No | Default: false |
containsSyntheticMedia | boolean | No | Whether media contains AI-generated content. |
playlistIds | array of strings | No | YouTube playlist IDs to add the video to. Get from subaccounts. |
thumbnailUrl | string | No | Publicly accessible image URL to use as the video thumbnail. Requires a verified YouTube account with custom thumbnail capabilities. |
YouTube "description" comes from the content.text field. Tags are not supported -- YouTube recommends against relying on tags for discovery (source).
Webhook
This target is available through REST, not blotato_create_post. Set content.platform to "other" and target.targetType to "webhook". It sends post content to your URL. It is separate from the DM automation webhook action and does not subscribe you to account-wide events.
| Field | Type | Required | Description |
|---|---|---|---|
targetType | "webhook" | Yes | |
url | string | Yes | The webhook URL to send the post data. |
Response
Status Code: 201 Created
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scheduledTime": "2025-03-10T15:30:00Z"
}
| Field | Type | Description |
|---|---|---|
postSubmissionId | string | ID of the post submission. Use it to poll Get Post Status for publishing progress. |
scheduledTime | string | The resolved UTC time the post publishes. Absent when the post publishes immediately. |
scheduledTime tells you the slot Blotato picked when you send useNextFreeSlot: true, so you read the scheduled time without a follow-up call.
Failed posts are visible at https://my.blotato.com/posts?status=failed. The most common cause of failed posts is incorrect JSON structure.
Examples
1. Simplest Post (Twitter, text only)
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Hello, world!",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
2. Instagram Post with Images
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98434",
"content": {
"text": "Check out these photos!",
"mediaUrls": [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg"
],
"platform": "instagram"
},
"target": {
"targetType": "instagram",
"firstComment": "Full guide: https://blotato.com"
}
}
}
Posting multiple images to Instagram creates a carousel.
firstComment auto-posts as the first comment right after the post goes live, a common way to share a link without putting it in the caption.
3. Facebook Page Post
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98433",
"content": {
"text": "New product announcement!",
"mediaUrls": ["https://example.com/product.jpg"],
"platform": "facebook"
},
"target": {
"targetType": "facebook",
"pageId": "123456789"
}
}
}
Get accountId and pageId from the Accounts endpoints.
4. TikTok Post (all required fields)
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98435",
"content": {
"text": "Tips for productivity",
"mediaUrls": ["https://example.com/video.mp4"],
"platform": "tiktok"
},
"target": {
"targetType": "tiktok",
"privacyLevel": "PUBLIC_TO_EVERYONE",
"disabledComments": false,
"disabledDuet": false,
"disabledStitch": false,
"isBrandedContent": false,
"isYourBrand": false,
"isAiGenerated": true
}
}
}
5. Scheduled Post
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "This will go live later",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
},
"scheduledTime": "2025-12-25T15:00:00Z"
}
6. Twitter Thread
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Here is a thread about AI content creation (1/3)",
"mediaUrls": [],
"platform": "twitter",
"additionalPosts": [
{
"text": "First, research your topic using reliable sources (2/3)",
"mediaUrls": []
},
{
"text": "Then, create visuals and publish across platforms (3/3)",
"mediaUrls": []
}
]
},
"target": {
"targetType": "twitter"
}
}
}
Threads work for Twitter, Bluesky, and Threads.
7. Schedule at Next Free Slot
POST https://backend.blotato.com/v2/posts HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"post": {
"accountId": "98432",
"content": {
"text": "Scheduled to the next free slot",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
},
"useNextFreeSlot": true
}
useNextFreeSlot and scheduledTime are top-level fields, not inside post.
Get Post /v2/posts/:postSubmissionId
Check Post Status
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /posts/:postSubmissionId
Method: GET
Rate Limit: 60 requests / minute
Description
Poll this endpoint to check the publishing status of a post. After submitting a post with Create Post, use the returned postSubmissionId to track its progress.
The lookup checks failed, published, and scheduled records belonging to the authenticated Blotato user. If none matches, it returns in-progress. This fallback does not confirm a live queue job or validate a guessed submission ID. Use the original create response and account credentials.
Request
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
postSubmissionId | string | Yes | The post submission ID returned by the Create Post endpoint. |
Responses
Success Response
Status Code: 200 OK
The response shape depends on the current status:
Published (terminal - success):
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "published",
"publicUrl": "https://x.com/user/status/123456"
}
Failed (terminal - error):
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "failed",
"errorMessage": "Unsupported media type"
}
In Progress (keep polling):
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "in-progress"
}
Scheduled (queued for a future time):
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "scheduled",
"scheduledTime": "2025-03-10T15:30:00Z"
}
Response Keys
| Field | Type | Description |
|---|---|---|
postSubmissionId | string | The post submission ID. |
status | string | One of: in-progress, scheduled, published, failed. |
scheduledTime | string | The scheduled publish time. Present when status is scheduled. |
publicUrl | string | URL returned for a published result, when available. The field is optional. |
errorMessage | string | Description of the failure. Present when status is failed. |
Polling Strategy
- Wait at least 10 seconds between status requests.
- Continue while status is
in-progress, within a defined attempt or elapsed-time limit. Verify the ID came from the original create response. - If status is
scheduled, report the returnedscheduledTimeand stop this polling loop. Scheduling is confirmed, not publication. - Stop when status is
published(success) orfailed(error). - On
failed, inspecterrorMessageand the destination before deciding whether a corrected or delayed retry is appropriate. Do not repeat a create request blindly.
If the result remains unresolved, retain the ID and follow publishing-status diagnosis. A polling deadline is not proof of failure.
Failed posts are also visible at https://my.blotato.com/posts?status=failed.
Example
GET https://backend.blotato.com/v2/posts/a1b2c3d4-e5f6-7890-abcd-ef1234567890 HTTP/1.1
blotato-api-key: YOUR_API_KEY
List Posts /v2/posts
List Posts
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /posts
Method: GET
Rate Limit: 60 requests / minute
Description
Returns 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.
To check the status of a single post by its postSubmissionId, use Get Post Status instead.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
since | string | No | Only include posts whose post time is on or after this ISO 8601 timestamp. Defaults to 7 days ago. |
until | string | No | Only include posts whose post time is on or before this ISO 8601 timestamp. Defaults to 7 days from now. |
limit | integer | No | Number of items per page. Min: 1, Max: 250. Default: 50. |
cursor | string | No | Pagination cursor from a previous response. Pass it to fetch the next page. |
status | string[] | No | Filter by status. One or more of scheduled, published, failed. Pass multiple values to include any of them. Omit to include all statuses. |
platform | string[] | No | Filter by social media platform. One or more of twitter, instagram, linkedin, facebook, tiktok, pinterest, threads, bluesky, youtube. Pass multiple values to include any of them. Omit to include all platforms. |
Array query parameters are repeated, e.g. ?status=scheduled&status=published.
Response
Status Code: 200 OK
{
"items": [
{
"id": "98432",
"postTime": "2026-04-01T14:00:00.000Z",
"platform": "twitter",
"text": "Scheduled post content",
"mediaUrls": [],
"account": { "id": "123", "name": "Blotato", "subaccount": null },
"state": {
"type": "scheduled"
}
},
{
"id": "98431",
"postTime": "2026-03-30T09:15:00.000Z",
"platform": "instagram",
"text": "Check out this image!",
"mediaUrls": ["https://example.com/image1.jpg"],
"account": { "id": "456", "name": "Blotato", "subaccount": null },
"state": {
"type": "published",
"postUrl": "https://instagram.com/p/abc123",
"analytics": {
"latest": {
"fetchedAt": "2026-09-30T12:00:00Z",
"metrics": { "viewsCount": "18400", "likesCount": "920" }
},
"history": []
}
}
},
{
"id": "98430",
"postTime": "2026-03-29T11:00:00.000Z",
"platform": "tiktok",
"text": "Failed upload",
"mediaUrls": ["https://example.com/clip.mp4"],
"account": null,
"state": {
"type": "failed",
"errorMessage": "Unsupported media type"
}
}
],
"cursor": "MjAyNi0wMy0yOVQxMTowMDow..."
}
Response Keys
| Field | Type | Description |
|---|---|---|
items | array | List of posts within the time window, ordered by postTime descending. |
items[].id | string | The post's identifier. Distinct per state.type: scheduled posts use the schedule ID, published posts use the published post ID, failed posts use the failed post ID. |
items[].postTime | string | ISO 8601 UTC timestamp. For scheduled posts this is the planned publish time; for published posts it is when the post was published; for failed posts it is when the failure was recorded. |
items[].platform | string | Social media platform. |
items[].text | string | The post text. |
items[].mediaUrls | string[] | URLs of attached media (images, video). Empty when text-only. |
items[].account | object or null | Connected account with id, name, and subaccount. Null if the account is no longer connected. |
items[].state | object | Discriminated union; see below. |
cursor | string | Pagination cursor. Pass this as the cursor query parameter to fetch the next page. Absent when there are no more pages. |
state object
The shape depends on state.type:
Scheduled
{ "type": "scheduled" }
Published
{ "type": "published", "postUrl": "https://instagram.com/p/abc123", "analytics": null }
| Field | Type | Description |
|---|---|---|
postUrl | string | null | The live URL of the published post. Null if the platform did not return one. |
analytics | object | null | Latest snapshot under latest and every snapshot, oldest first, under history. Null if metrics have not been collected or analytics is unavailable. |
Failed
{ "type": "failed", "errorMessage": "Unsupported media type" }
| Field | Type | Description |
|---|---|---|
errorMessage | string | null | Human-readable description of the failure. |
Errors
| Status | Reason |
|---|---|
422 | Invalid since, until, or cursor value. |
Examples
Default request
GET https://backend.blotato.com/v2/posts HTTP/1.1
blotato-api-key: YOUR_API_KEY
Only published Twitter posts in the last 30 days
GET https://backend.blotato.com/v2/posts?since=2026-04-12T00:00:00Z&status=published&platform=twitter HTTP/1.1
blotato-api-key: YOUR_API_KEY
Scheduled or published, multi-platform
GET https://backend.blotato.com/v2/posts?status=scheduled&status=published&platform=twitter&platform=instagram HTTP/1.1
blotato-api-key: YOUR_API_KEY
Walking pages
GET https://backend.blotato.com/v2/posts?limit=100 HTTP/1.1
blotato-api-key: YOUR_API_KEY
If the response contains a cursor, pass it on the next request:
GET https://backend.blotato.com/v2/posts?limit=100&cursor=MjAyNi0wMy0yOVQxMTowMDow... HTTP/1.1
blotato-api-key: YOUR_API_KEY
When the response omits cursor, you have reached the end of the list.
List Published Posts /v2/published-posts
List your published posts, filtered by text and platform, with each post's latest analytics snapshot attached. Use this to find a published post and its id, or to browse recent posts with their current metrics.
For engagement rankings and full metric history, see Analytics.
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /published-posts
Method: GET
Description
Returns your published posts, newest or oldest first, filtered by an optional full-text query and platform. Each item carries its latest metrics snapshot. Results use offset-based pagination with a total count.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
query | string | No | Full-text search over post content. Omit to include all posts. |
platform | string | No | Filter to one platform. Omit to include all platforms. |
sortBy | string | No | Sort order: newest or oldest. Default newest. |
offset | integer | No | Number of posts to skip before the page. Default 0. |
limit | integer | No | Number of posts to return. Min: 1, Max: 100. Default: 20. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "98431",
"content": "Check out this image!",
"postUrl": "https://instagram.com/p/abc123",
"platform": "instagram",
"createdAt": "2026-05-30T09:15:00.000Z",
"mediaUrls": ["https://example.com/image1.jpg"],
"latestMetrics": {
"fetchedAt": "2026-06-11T12:00:00.000Z",
"metrics": { "likesCount": "1240", "reachCount": "53000" }
},
"metricsHistory": []
}
],
"count": 137
}
| Field | Type | Description |
|---|---|---|
items | array | Published posts for this page. |
items[].id | string | The published post id. Pass it to Get Post Analytics for full metric history. |
items[].content | string | The post text. |
items[].postUrl | string or null | Live URL of the published post. Null if the platform did not return one. |
items[].platform | string | Social media platform. |
items[].createdAt | string | ISO 8601 timestamp when the post was published. |
items[].mediaUrls | string[] | URLs of attached media. Empty when text-only. |
items[].latestMetrics | object | The most recent metrics snapshot. Absent if no metrics have been collected yet. See Metrics. |
items[].metricsHistory | array | Collected snapshots, oldest first. Each is { fetchedAt, metrics }. |
count | integer | Total number of posts matching your search, across all pages. |
To page through results, increase offset by limit on each call until offset reaches count.
Errors
| Status | Reason |
|---|---|
422 | Invalid sortBy, offset, or limit value. |
Example
GET https://backend.blotato.com/v2/published-posts?query=summer&platform=instagram&limit=20 HTTP/1.1
blotato-api-key: YOUR_API_KEY
Get a Published Post
URL: /published-posts/:id
Method: GET
Returns 1 published post by its Blotato published-post ID.
{
"publishedPost": {
"id": "98431",
"platform": "instagram",
"content": "Check out this image!",
"mediaUrls": ["https://example.com/image1.jpg"],
"postUrl": "https://instagram.com/p/abc123",
"createdAt": "2026-05-30T09:15:00.000Z",
"rawPost": null
}
}
rawPost contains the original publish payload for posts published through Blotato and is null for other posts. The endpoint returns 404 when the ID does not exist or does not belong to the authenticated user.
Analytics /v2/analytics
Blotato collects engagement analytics for your published posts on 8 platforms: Twitter/X, Instagram, Facebook, Threads, Bluesky, TikTok, YouTube, and Pinterest. Analytics for LinkedIn are not available yet. Four read-only endpoints expose this data:
- List Top Performing Posts —
GET /v2/analytics - List Performance by Platform —
GET /v2/analytics/platforms - Get Analytics Summary —
GET /v2/analytics/summary - Get Post Analytics —
GET /v2/posts/{id}/analytics
Analytics is available on all paid plans, both in the Analytics dashboard and via the API documented below. Fair usage limits may apply in the future.
For a web-app and AI-agent walkthrough, see Analytics.
Both endpoints return the latest snapshot Blotato has already collected. They do not trigger a fresh fetch from the social platform.
Using analytics from Make.com or n8n
The official Blotato Make.com module does not include analytics yet. To pull analytics from a Make scenario, call the two endpoints on this page with Make's HTTP module, passing your API key in the blotato-api-key header. The same approach works in n8n with the HTTP Request node.
Collection schedule
Blotato collects a snapshot of each post's metrics at fixed checkpoints, measured from when the post publishes. Higher plans collect more often and keep collecting longer.
| Plan | Checkpoints per post | Collection window | Cadence |
|---|---|---|---|
| Starter | 4 | 30 days | Day 1, then days 7, 14, and 30 |
| Creator | 18 | 30 days | 2 hours, daily through day 8, then every 2-3 days through day 30 |
| Agency | 20 | 90 days | 2 and 6 hours, daily through day 8, every 2-3 days through day 30, then day 90 |
Full checkpoint list per plan:
- Starter: 1d, 7d, 14d, 30d
- Creator: 2h, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 10d, 12d, 14d, 17d, 20d, 22d, 24d, 27d, 30d
- Agency: 2h, 6h, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 10d, 12d, 14d, 17d, 20d, 22d, 24d, 27d, 30d, 90d
Each checkpoint adds a small random offset to spread out collection, so exact timing varies by a few minutes on the early checkpoints and up to a day on the 30-day and 90-day ones. After the final checkpoint, Blotato stops collecting and the last snapshot stays as the post's metrics.
Posts stuck on "Analytics pending"
"Analytics pending" means no metric history is available. It does not identify the cause.
- Check the platform and plan against the supported metrics.
- Check whether the post was published through Blotato with analytics enabled.
- Compare the post's age with its plan's checkpoints.
- Inspect
lastErrorand the account's connection state. Reconnect when authorization is missing or expired, not as a repeated generic fix. - If the expected checkpoint has passed and no cause is established, give support the published post ID, publication time, platform, plan, last fetch time, and error.
Reconnection does not guarantee a 24-48-hour backfill or a restart of every historical post's schedule. See new connections and pending data.
YouTube view counts trail the public count
For YouTube, Blotato reads the YouTube Analytics API, which reports only finalized views after YouTube filters spam and invalid traffic. The count on the YouTube watch page updates in near real time and includes views YouTube has not validated yet, so it reads higher. The two numbers are not expected to match, and the gap narrows as YouTube finalizes more data.
See: Why is my YouTube view count in Blotato lower than on YouTube?
List Top Performing Posts
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /analytics
Method: GET
Description
Returns your top performing published posts, ordered by the requested metric over a time range. Each item includes its latest metrics snapshot and full snapshot history.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
since | string | No | Only include posts published on or after this ISO 8601 timestamp. Defaults to 30 days ago. |
until | string | No | Only include posts published on or before this ISO 8601 timestamp. Defaults to now. |
platform | string | No | Filter to one platform: twitter, instagram, facebook, threads, bluesky, tiktok, youtube, or pinterest. Omit to include all platforms. Analytics for linkedin are not available yet, so filtering to it returns no metrics. |
sortBy | string | No | Metric to rank by. One of likes_count, comments_count, views_count, reach_count. Default: views_count. For Twitter/X, comments_count uses replies_count when comments are not reported, and views_count uses impressions_count when views are not reported. |
limit | integer | No | Number of posts to return. Min: 1, Max: 100. Default: 20. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "98431",
"content": "Check out this image!",
"postUrl": "https://instagram.com/p/abc123",
"platform": "instagram",
"createdAt": "2026-05-30T09:15:00.000Z",
"mediaUrls": ["https://example.com/image1.jpg"],
"latestMetrics": {
"fetchedAt": "2026-06-11T12:00:00.000Z",
"metrics": {
"likesCount": "1240",
"commentsCount": "85",
"reachCount": "53000",
"savesCount": "310"
}
},
"metricsHistory": [
{
"fetchedAt": "2026-06-10T12:00:00.000Z",
"metrics": { "likesCount": "1190", "reachCount": "51200" }
},
{
"fetchedAt": "2026-06-11T12:00:00.000Z",
"metrics": { "likesCount": "1240", "reachCount": "53000" }
}
]
}
]
}
Response Keys
| Field | Type | Description |
|---|---|---|
items | array | Published posts, ordered by the requested sortBy metric (highest first). Twitter/X rankings use replies_count as the comments fallback and impressions_count as the views fallback. |
items[].id | string | The published post id. Pass this to Get Post Analytics. |
items[].content | string | The post text. |
items[].postUrl | string | null | Live URL of the published post. Null if the platform did not return one. |
items[].platform | string | Social media platform. |
items[].createdAt | string | ISO 8601 timestamp when the post was published. |
items[].mediaUrls | string[] | URLs of attached media. Empty when text-only. |
items[].latestMetrics | object | The most recent metrics snapshot. Absent if no metrics have been collected yet. See Metrics. |
items[].metricsHistory | array | All collected snapshots, oldest first. Each is { fetchedAt, metrics }. |
Errors
| Status | Reason |
|---|---|
422 | Invalid since, until, sortBy, or limit value. |
Example
GET https://backend.blotato.com/v2/analytics?sortBy=views_count&platform=instagram&limit=10 HTTP/1.1
blotato-api-key: YOUR_API_KEY
List Performance by Platform
URL: /analytics/platforms
Method: GET
Returns 1 entry per platform with analytics, ordered by engagement. Totals use the latest snapshot of each post published in the window.
| Field | Type | Required | Description |
|---|---|---|---|
since | string | No | Include posts published on or after this ISO 8601 timestamp. Defaults to 24 hours ago. |
until | string | No | Include posts published on or before this ISO 8601 timestamp. Defaults to now. |
bucket | string | No | Time bucket size: hour or day. Defaults to hour. |
Each item contains platform, postsCount, engagementsCount, likesCount, commentsCount, viewsCount, and buckets. Counts are strings except postsCount. viewsCount is null when the platform reports neither views nor impressions. Engagements are the sum of likes, comments or replies, shares, and saves.
Get Analytics Summary
URL: /analytics/summary
Method: GET
Returns published and failed post counts for a time window, both in total and grouped by platform and time bucket. It also returns metric totals from each published post's latest snapshot.
| Field | Type | Required | Description |
|---|---|---|---|
since | string | No | Include posts published or failed on or after this ISO 8601 timestamp. Defaults to 30 days ago. |
until | string | No | Include posts published or failed on or before this ISO 8601 timestamp. Defaults to now. |
bucket | string | No | Time bucket size: hour or day. Defaults to hour. |
The response contains publishedCount, failedCount, platforms, buckets, and metrics. metrics contains postsCount, viewsCount, likesCount, and commentsCount, or is null when analytics is unavailable.
Get Post Analytics
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /posts/{id}/analytics
Method: GET
Description
Returns the latest metrics and full snapshot history for a single published post.
The id is the published post id, which you get from the items[].id field of List Top Performing Posts or List Posts (published items). It is not the postSubmissionId returned when you publish.
If your request returns only postSubmissionId, status, and publicUrl with no metrics fields, you called Get Post Status instead of this analytics endpoint. Get Post checks publish status with the postSubmissionId. Analytics uses the published post id from List Posts or List Top Performing Posts.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The published post ID from items[].id in List Top Performing Posts or a published item in List Posts. Do not substitute a postSubmissionId. The analytics path ends in /analytics, whereas the publishing-status path does not. |
Response
Status Code: 200 OK
{
"publishedPostId": "12345",
"platform": "instagram",
"lastFetchedAt": "2026-06-11T12:00:00.000Z",
"lastError": null,
"metrics": {
"viewsCount": "18400",
"likesCount": "920",
"commentsCount": "47",
"reachCount": "56200"
},
"history": [
{
"fetchedAt": "2026-06-10T12:00:00.000Z",
"metrics": { "viewsCount": "12100", "likesCount": "640" }
},
{
"fetchedAt": "2026-06-11T12:00:00.000Z",
"metrics": { "viewsCount": "18400", "likesCount": "920" }
}
]
}
Response Keys
| Field | Type | Description |
|---|---|---|
publishedPostId | string | The id of the published post. |
platform | string | Social media platform. |
lastFetchedAt | string | null | ISO 8601 timestamp of the last snapshot stored successfully. A failed fetch leaves this unchanged, so it reflects the last success, not the last attempt. Check lastError for the most recent failure. |
lastError | string | null | The last error Blotato hit while fetching metrics for this post, if any. |
metrics | object | null | Latest metrics snapshot. See Metrics and Empty vs null metrics. |
history | array | All collected snapshots, oldest first. Each is { fetchedAt, metrics }. |
Errors
| Status | Reason |
|---|---|
404 | No published post with that id, it does not belong to your account, or your plan does not include analytics. |
Example
GET https://backend.blotato.com/v2/posts/12345/analytics HTTP/1.1
blotato-api-key: YOUR_API_KEY
Metrics
Every metric field is optional and only appears when the platform reports it for that post. Count metrics are returned as strings to preserve large integers (e.g. "18400"). Rate and percentage metrics are returned as numbers, and breakdown metrics (such as facebookPostReactionsByType) return an object mapping each bucket to a count, e.g. { "like": "13", "haha": "2" }.
A metric value of 0 is real and is always returned. It means zero, not missing.
Empty vs null metrics
An empty metrics object ({}) is not the same as metrics: null.
metrics: null-- no analytics snapshot has been stored yet.metrics: {}-- a snapshot exists, but no metric values are being returned. Two causes: every value came back empty from the platform, or your plan returns a reduced metric set.
Common metrics like viewsCount, likesCount, and reachCount apply across platforms. Each platform also returns its own metrics, prefixed with the platform name — for example twitterRetweetsCount or blueskyRepostsCount.
See the Metrics Reference for the full list of common and platform-specific metrics.
Platform-specific coverage depends on your plan. The Starter plan returns a limited set of these metrics. The Creator and Agency plans return every platform-specific metric and breakdown. See the Metrics Reference for the field-level breakdown.
Inspect the metrics object in the response for the set available for your post.
Related
- List Posts — list scheduled, published, and failed posts; published items carry the
idused by Get Post Analytics. - List Published Posts — full-text search over your published posts with the latest analytics snapshot attached.
Analytics Metrics Reference
This page lists every metric field that can appear in an analytics snapshot returned by List Top Performing Posts and Get Post Analytics.
Metrics live inside a snapshot's metrics object:
{
"fetchedAt": "2026-06-11T12:00:00.000Z",
"metrics": {
"viewsCount": "18400",
"likesCount": "920",
"twitterRetweetsCount": "45"
}
}
How to read this reference
- Every field is optional. A metric only appears when the platform reports it for that specific post and when it's covered under your Blotato plan, so most snapshots contain a small subset of the fields below.
- Counts are strings. Count metrics are returned as strings (e.g.
"18400") to preserve large integers without precision loss. - Rates and percentages are numbers. Ratios (
0–1) and percentages (0–100) are returned as JSON numbers. - Breakdown metrics are objects. A breakdown maps each bucket to a count string, e.g.
{ "like": "13", "haha": "2" }. On the Published page these render as a bar chart with one bar per bucket. - Per-media metrics are arrays. A few Twitter video metrics are arrays indexed by media position in the post (upload order across the whole thread). Entries are
nullfor media items that are not videos.
Analytics are currently collected for Twitter/X, Instagram, Facebook, Threads, Bluesky, TikTok, YouTube, and Pinterest. Instagram and TikTok report only the common metrics and have no platform-specific fields. The LinkedIn fields below are part of the API schema but are not populated yet.
Common metrics
Reported across platforms whenever the platform exposes them.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
viewsCount | string | Views. | ✓ | ✓ | ✓ |
impressionsCount | string | Impressions. | ✓ | ✓ | ✓ |
reachCount | string | Unique accounts reached. | ✓ | ✓ | ✓ |
likesCount | string | Likes. | ✓ | ✓ | ✓ |
commentsCount | string | Comments. | ✓ | ✓ | ✓ |
repliesCount | string | Replies. | ✓ | ✓ | ✓ |
sharesCount | string | Shares. | ✓ | ✓ | ✓ |
savesCount | string | Saves / bookmarks. | ✓ | ✓ | ✓ |
clicksCount | string | Link or content clicks. | ✓ | ✓ | ✓ |
followsCount | string | Follows gained from the post. | ✓ | ✓ | ✓ |
playsCount | string | Video / audio plays. | ✓ | ✓ | ✓ |
profileVisitsCount | string | Profile visits driven by the post. | ✓ | ✓ | ✓ |
profileActivityCount | string | Profile actions driven by the post. | ✓ | ✓ | ✓ |
navigationsCount | string | In-post navigation actions (e.g. carousel swipes). | ✓ | ✓ | ✓ |
interactionsSum | string | Total interactions. | ✓ | ✓ | ✓ |
viewTimeMsSum | string | Total watch time, milliseconds. | ✓ | ✓ | ✓ |
watchTimeMsAvg | string | Average watch time, milliseconds. | ✓ | ✓ | ✓ |
Twitter / X
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
twitterRetweetsCount | string | Retweets. | ✓ | ✓ | ✓ |
twitterQuotesCount | string | Quote tweets. | ✓ | ✓ | ✓ |
Per-media video metrics. Each is an array indexed by media position in the post; null entries mark non-video media.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
twitterPerMediaVideoViewsCount | (string | null)[] | Video views per media item. | ✓ | ✓ | |
twitterPerMediaVideoPlaybackStartCount | (string | null)[] | Playbacks started per media item. | ✓ | ✓ | |
twitterPerMediaVideoPlayback25Count | (string | null)[] | Playbacks reaching 25% per media item. | ✓ | ✓ | |
twitterPerMediaVideoPlayback50Count | (string | null)[] | Playbacks reaching 50% per media item. | ✓ | ✓ | |
twitterPerMediaVideoPlayback75Count | (string | null)[] | Playbacks reaching 75% per media item. | ✓ | ✓ | |
twitterPerMediaVideoPlaybackCompleteCount | (string | null)[] | Playbacks completed per media item. | ✓ | ✓ |
Bluesky
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
blueskyRepostsCount | string | Reposts. | ✓ | ✓ | ✓ |
blueskyQuotesCount | string | Quote posts. | ✓ | ✓ | ✓ |
Threads
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
threadsRepostsCount | string | Reposts. | ✓ | ✓ | ✓ |
threadsQuotesCount | string | Quote posts. | ✓ | ✓ | ✓ |
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
facebookPostMediaViewsCount | string | Media views on the post. | ✓ | ✓ | |
facebookPostMediaViewsUniqueCount | string | Unique media views on the post. | ✓ | ✓ | |
facebookPostReactionsByType | object | Reactions broken down by type (e.g. like, love, haha). | ✓ | ✓ |
Video and Reels metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
facebookBlueReelsPlaysCount | string | Reel plays. | ✓ | ✓ | |
facebookFbReelsReplaysCount | string | Reel replays. | ✓ | ✓ | |
facebookFbReelsTotalPlaysCount | string | Total reel plays (plays plus replays). | ✓ | ✓ | |
facebookPostVideoWatchTimeMsAvg | string | Average video watch time, milliseconds. | ✓ | ✓ | |
facebookPostVideoFollowersCount | string | Followers gained from the video. | ✓ | ✓ | |
facebookPostVideoLikesByReactionType | object | Video likes broken down by reaction type. | ✓ | ✓ | |
facebookPostVideoSocialActionsByType | object | Video social actions broken down by type. | ✓ | ✓ | |
facebookPostVideoViewTimeMsSum | string | Total video view time, milliseconds. | ✓ | ✓ | |
facebookTotalVideoViewsCount | string | Total video views. | ✓ | ✓ | |
facebookTotalVideoViewsUniqueCount | string | Unique video views. | ✓ | ✓ | |
facebookTotalVideoViewsAutoplayedCount | string | Autoplayed video views. | ✓ | ✓ | |
facebookTotalVideoViewsClickedToPlayCount | string | Click-to-play video views. | ✓ | ✓ | |
facebookTotalVideoViewsSoundOnCount | string | Video views with sound on. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsCount | string | Complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsUniqueCount | string | Unique complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsAutoplayedCount | string | Autoplayed complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsClickedToPlayCount | string | Click-to-play complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsOrganicCount | string | Organic complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsOrganicUniqueCount | string | Unique organic complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsPaidCount | string | Paid complete video views. | ✓ | ✓ | |
facebookTotalVideoCompleteViewsPaidUniqueCount | string | Unique paid complete video views. | ✓ | ✓ | |
facebookTotalVideoViews10sCount | string | Video views of at least 10 seconds. | ✓ | ✓ | |
facebookTotalVideoViews10sUniqueCount | string | Unique 10-second video views. | ✓ | ✓ | |
facebookTotalVideoViews10sAutoplayedCount | string | Autoplayed 10-second video views. | ✓ | ✓ | |
facebookTotalVideoViews10sClickedToPlayCount | string | Click-to-play 10-second video views. | ✓ | ✓ | |
facebookTotalVideoViews10sOrganicCount | string | Organic 10-second video views. | ✓ | ✓ | |
facebookTotalVideoViews10sPaidCount | string | Paid 10-second video views. | ✓ | ✓ | |
facebookTotalVideoViews10sSoundOnCount | string | 10-second video views with sound on. | ✓ | ✓ | |
facebookTotalVideoViews15sCount | string | Video views of at least 15 seconds. | ✓ | ✓ | |
facebookTotalVideoViews60sExcludesShorterCount | string | Video views of at least 60 seconds (excludes shorter). | ✓ | ✓ | |
facebookTotalVideoWatchTimeMsAvg | string | Average total video watch time, milliseconds. | ✓ | ✓ | |
facebookTotalVideoViewTimeMsSum | string | Total video view time, milliseconds. | ✓ | ✓ | |
facebookTotalVideoViewTimeOrganicMsSum | string | Organic video view time, milliseconds. | ✓ | ✓ | |
facebookTotalVideoViewTimePaidMsSum | string | Paid video view time, milliseconds. | ✓ | ✓ | |
facebookTotalVideoStoriesByActionType | object | Video stories (shares/comments/etc.) broken down by action type. | ✓ | ✓ | |
facebookTotalVideoReactionsByType | object | Video reactions broken down by type. | ✓ | ✓ | |
facebookTotalVideoViewTimeMsByAgeBucketAndGender | object | Video view time broken down by age bucket and gender. | ✓ | ✓ | |
facebookTotalVideoViewTimeMsByRegionId | object | Video view time broken down by region. | ✓ | ✓ | |
facebookTotalVideoViewsByDistributionType | object | Video views broken down by distribution type. | ✓ | ✓ |
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
linkedinFirstLevelCommentsCount | string | First-level comments (excludes replies). | ✓ | ✓ | ✓ |
linkedinReactionsByType | object | Reactions broken down by type (e.g. like, praise, empathy). | ✓ | ✓ |
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
pinterestPinClicksCount | string | Pin clicks. | ✓ | ✓ | |
pinterestReactionsCount | string | Reactions. | ✓ | ✓ | ✓ |
pinterestVideoP95ViewsCount | string | Video views reaching 95% of the video. | ✓ | ✓ | |
pinterestVideo10sViewsCount | string | Video views of at least 10 seconds. | ✓ | ✓ | |
pinterestVideoMrcViewsCount | string | MRC-standard video views. | ✓ | ✓ | |
pinterestVideoV50WatchTimeMsSum | string | Watch time for views past 50%, milliseconds. | ✓ | ✓ | |
pinterestSaveRate | number | Saves divided by impressions, a 0–1 ratio. | ✓ | ✓ |
YouTube
YouTube metrics come from the YouTube Analytics API, which reports only finalized views after YouTube filters spam and invalid traffic. viewsCount for a YouTube post therefore reads lower than the count on the YouTube watch page, and the gap narrows as YouTube finalizes more data. See: Analytics.
Post-level metrics.
| Field | Type | Description | Starter | Creator | Agency |
|---|---|---|---|---|---|
youtubeDislikesCount | string | Dislikes. | ✓ | ✓ | |
youtubeSubscribersLostCount | string | Subscribers lost from the video. | ✓ | ✓ | |
youtubeVideosAddedToPlaylistsCount | string | Times the video was added to a playlist. | ✓ | ✓ | |
youtubeVideosRemovedFromPlaylistsCount | string | Times the video was removed from a playlist. | ✓ | ✓ | |
youtubeRedViewsCount | string | YouTube Premium (Red) views. | ✓ | ✓ | |
youtubeRedViewTimeMsSum | string | YouTube Premium (Red) watch time, milliseconds. | ✓ | ✓ | |
youtubeEngagedViewsCount | string | Engaged views. | ✓ | ✓ | |
youtubeAverageViewPercentage | number | Average percentage of the video watched, 0–100. | ✓ | ✓ | |
youtubeCardClicksCount | string | Card clicks. | ✓ | ✓ | |
youtubeCardImpressionsCount | string | Card impressions. | ✓ | ✓ | |
youtubeCardClickRate | number | Card clicks divided by impressions, a 0–1 ratio. | ✓ | ✓ | |
youtubeCardTeaserClicksCount | string | Card teaser clicks. | ✓ | ✓ | |
youtubeCardTeaserImpressionsCount | string | Card teaser impressions. | ✓ | ✓ | |
youtubeCardTeaserClickRate | number | Card teaser clicks divided by impressions, a 0–1 ratio. | ✓ | ✓ | |
youtubeAnnotationClicksCount | string | Annotation clicks. | ✓ | ✓ | |
youtubeAnnotationClickableImpressionsCount | string | Clickable annotation impressions. | ✓ | ✓ | |
youtubeAnnotationClosesCount | string | Annotation closes. | ✓ | ✓ | |
youtubeAnnotationClosableImpressionsCount | string | Closable annotation impressions. | ✓ | ✓ | |
youtubeAnnotationImpressionsCount | string | Annotation impressions. | ✓ | ✓ | |
youtubeAnnotationClickThroughRate | number | Annotation click-through rate, a 0–1 ratio. | ✓ | ✓ | |
youtubeAnnotationCloseRate | number | Annotation close rate, a 0–1 ratio. | ✓ | ✓ |
Related
- Analytics — the two endpoints that return these metrics.
- List Top Performing Posts —
GET /v2/analytics - Get Post Analytics —
GET /v2/posts/{id}/analytics
Comments /v2/comments
Blotato allows you to read and post comments on your published Instagram posts and Facebook Page posts. Twitter/X, TikTok, LinkedIn, Pinterest, Threads, Bluesky, and YouTube are not supported at this time. Three endpoints let you list, read, and post comments:
- List Comments —
GET /v2/comments - Get Comment —
GET /v2/comments/:commentId - Post Comment —
POST /v2/comments
Comments are available on all paid plans.
To manage Instagram and Facebook comments in the Blotato web app, see Comments and Messaging Inbox.
Blotato does not backfill comments. It starts capturing comments once your account has comments enabled and you connect or reconnect your account. Comments left before then do not appear in these endpoints.
Blotato retains comments for up to 45 days. Comments older than 45 days are not available through these endpoints.
The /comments endpoints cover two directions:
- Inbound comments your audience leaves on your posts. These have
isAuthor: false. - Outbound comments you post through Blotato. These have
isAuthor: true.
The comments API lists and posts top-level comments and one level of replies. You can reply to a top-level comment on your post, but you cannot reply to a reply.
Before You Start
Blotato must have permissions to read and post comments on your account before you can use the Blotato comments endpoints.
If you connected your account before comments launched, reconnect it so Blotato has the new permission.
- For Instagram, see Connect Instagram.
- For Facebook, see Connect Facebook.
List Comments
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /comments
Method: GET
Description
Returns your comments across connected accounts, ordered by creation time (most recent first). Use cursor-based pagination and the optional filters below.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum comments to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
platform | array | No | Filter by platform. Values: instagram, facebook. |
accountId | string | No | Filter to a single connected account. |
parentCommentId | string | No | Filter to direct replies to a single comment. |
postId | string | No | Filter to comments on a single post using its Blotato post ID. |
since | string | No | Only include comments created on or after this ISO 8601 timestamp. |
until | string | No | Only include comments created on or before this ISO 8601 timestamp. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "cmt_abc123",
"accountId": "98434",
"platform": "instagram",
"postId": "post_xyz789",
"platformPostId": "17851234567890",
"platformCommentId": "17899876543210",
"authorId": "1784000000",
"author": { "username": "jane.doe", "name": null },
"isAuthor": false,
"text": "Love this!",
"status": "posted",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-07-01T12:34:56Z"
}
],
"cursor": "eyJz..."
}
| Field | Type | Description |
|---|---|---|
items | array | List of comments. See Comment Object. |
cursor | string | Cursor for the next page. Absent when there are no more comments. |
Get Comment
Endpoint
URL: /comments/:commentId
Method: GET
Description
Fetches a single comment by its Blotato ID. The comment is an inbound reply from your audience or an outbound comment you posted through Blotato.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
commentId | string | Yes | Blotato ID of the comment. |
Response
Status Code: 200 OK
Returns a Comment Object.
Post Comment
Endpoint
URL: /comments
Method: POST
Description
Posts a comment on one of your published posts, or a reply to an existing top-level comment when you pass parentCommentId. Blotato queues the comment and posts it in the background, so the response returns status queued. Poll Get Comment with the returned id to confirm the comment reached posted or failed.
Request Body
{
"postId": "post_xyz789",
"text": "Thanks everyone!"
}
| Field | Type | Required | Description |
|---|---|---|---|
postId | string | Yes | Blotato ID of the published post to comment on. For a reply, use the parent comment's non-null postId. Otherwise, use List Posts, from items whose state.type is published. Do not substitute the social platform's post ID. |
text | string | Yes | Plain-text comment body. Instagram allows up to 2200 characters, Facebook up to 8000. |
parentCommentId | string | No | Blotato ID of a top-level, posted comment on the same post to reply to. Replies to replies are not supported. |
Response
Status Code: 201 Created
Returns a Comment Object with status queued.
Errors
| Status | Reason |
|---|---|
404 | The published post or parent comment was not found, or comments are not enabled for your account. |
422 | The post's platform does not support comments, the comment exceeds the platform's character limit, the parent comment is invalid, Blotato lacks the Instagram comment permission (error code 20203), or you reached your monthly active-contacts limit (error code 20101). |
429 | Rate limit exceeded (30 requests per minute). |
Replies and Your Contacts Limit
Replying to a comment from your audience counts the person as an active contact for the month. Your current account limit controls how many active contacts you reach. When you pass the limit, Post Comment returns 422 with error code 20101. Replying to your own comment does not count.
See Active Contacts for the definition, standard plan limits, and how to check your current limit.
Comment Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato comment ID. |
accountId | string | ID of the connected account the comment belongs to. |
platform | string | instagram or facebook. |
postId | string or null | Blotato ID of the tracked post. An incoming Instagram comment also creates this ID for posts published outside Blotato. A populated ID does not prove Blotato published the post. |
parentCommentId | string or null | Blotato ID of the parent comment when this comment is a reply. null for top-level comments. |
platformPostId | string | Social platform (e.g. Instagram) ID of the parent post. |
platformCommentId | string or null | Social platform (e.g. Instagram) ID of the comment. |
authorId | string or null | Social platform (e.g. Instagram) ID of the comment author. |
author | object | Who wrote the comment: username (Instagram) and name (Facebook). For your own comments this is your connected Instagram username or Facebook Page name, filled in once the comment is posted. Both null when the platform did not provide them. |
isAuthor | boolean | true when your connected account authored the comment. false for an audience reply. |
text | string | Comment text. |
status | string | Comment status. See Status Values. |
errorCode | integer or null | Set only when status is failed. See Comments Errors. |
errorMessage | string or null | Set only when status is failed. |
createdAt | string | ISO 8601 timestamp when the comment was created. |
Status Values
| Status | Meaning |
|---|---|
queued | Accepted and waiting to post. |
processing | Posting to the social platform. |
posted | Live on the social platform. |
failed | Did not post. See errorMessage. |
deleted | Removed from the social platform. |
Rate Limits
| Endpoint | Limit |
|---|---|
GET /comments | 60 / min |
GET /comments/:commentId | 60 / min |
POST /comments | 30 / min |
Messages /v2/messages
Blotato allows you to read and send direct messages on your Instagram account and Facebook Page. Twitter/X, TikTok, LinkedIn, Pinterest, Threads, Bluesky, and YouTube are not supported at this time. Five endpoints let you list conversations, read a conversation, list messages, read a message, and send a message:
- List Conversations —
GET /v2/conversations - Get Conversation —
GET /v2/conversations/:conversationId - List Messages —
GET /v2/messages - Get Message —
GET /v2/messages/:messageId - Send Message —
POST /v2/messages
Messages are available on all paid plans.
To manage Instagram and Facebook conversations in the Blotato web app, see Comments and Messaging Inbox.
To send automatic replies after a comment or incoming message, use DM Automations. You manage these automations in the web app or through an AI tool connected to Blotato MCP.
Each message has a direction:
- Incoming messages your contacts send you. These have
direction: "incoming". - Outgoing messages you send through Blotato. These have
direction: "outgoing".
You reply to people who already have a conversation with you. You send to a recipientId taken from an existing conversation or an incoming message, not to an arbitrary user. The social platform limits who you can message and when. See Messaging Windows.
Blotato retains messages for up to 45 days. Messages older than 45 days are not available through these endpoints.
Before You Start
Blotato must have permissions to read and send messages on your account before you can use the Blotato messaging endpoints.
If you connected your account before messaging launched, reconnect it so Blotato has the new permission.
- For Instagram, see Connect Instagram.
- For Facebook, see Connect Facebook.
List Conversations
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /conversations
Method: GET
Description
Returns your conversations across connected accounts, ordered by most recent activity. Use cursor-based pagination and the optional filters below.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum conversations to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
platform | string | No | Filter by platform. Values: instagram, facebook. |
accountId | string | No | Filter to a single connected account. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "cnv_abc123",
"accountId": "98434",
"platform": "instagram",
"participants": [
{
"id": "1784000000",
"name": "Jamie Rivera",
"username": "jamie.rivera",
"profileImageUrl": "https://example.com/avatar.jpg"
}
],
"createdAt": "2026-07-01T12:00:00Z",
"updatedAt": "2026-07-02T09:30:00Z"
}
],
"cursor": "eyJz..."
}
| Field | Type | Description |
|---|---|---|
items | array | List of conversations. See Conversation Object. |
cursor | string | Cursor for the next page. Absent when there are no more conversations. |
Get Conversation
Endpoint
URL: /conversations/:conversationId
Method: GET
Description
Fetches a single conversation by its Blotato ID.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
conversationId | string | Yes | Blotato ID of the conversation. |
Response
Status Code: 200 OK
Returns a Conversation Object.
List Messages
Endpoint
URL: /messages
Method: GET
Description
Returns your messages across connected accounts, ordered by creation time (most recent first). Use cursor-based pagination and the optional filters below.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum messages to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
conversationId | string | No | Filter to messages in a single conversation. |
platform | array | No | Filter by platform. Values: instagram, facebook. |
accountId | string | No | Filter to a single connected account. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "msg_abc123",
"conversationId": "cnv_abc123",
"platform": "instagram",
"direction": "incoming",
"senderId": "1784000000",
"recipientId": "17841400000000000",
"text": "Hi! Is this still available?",
"status": "delivered",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-07-02T09:30:00Z"
}
],
"cursor": "eyJz..."
}
| Field | Type | Description |
|---|---|---|
items | array | List of messages. See Message Object. |
cursor | string | Cursor for the next page. Absent when there are no more messages. |
Get Message
Endpoint
URL: /messages/:messageId
Method: GET
Description
Fetches a single message by its Blotato ID. Poll this after Send Message to check whether an outgoing message reached sent or failed.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
messageId | string | Yes | Blotato ID of the message. |
Response
Status Code: 200 OK
Returns a Message Object.
Send Message
Endpoint
URL: /messages
Method: POST
Description
Sends a direct message to one recipient. Blotato queues the message and sends it in the background, so the response returns status queued. Poll Get Message with the returned id to confirm the message reached sent or failed.
Send to a recipientId taken from an existing conversation or an incoming message. The social platform limits who you can message and when. See Messaging Windows.
Request Body
{
"accountId": "98434",
"recipientId": "1784000000",
"text": "Thanks for reaching out! Yes, it's available.",
"target": {
"targetType": "instagram"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | Blotato ID of the connected account the message is sent from. |
recipientId | string | Yes | Social platform (e.g. Instagram) ID of the recipient. Get it from an existing conversation or incoming message. |
text | string | Yes | Plain-text message body. Instagram messages are limited to 1000 bytes, Facebook to 2000 characters. With buttons attached, the limit drops to 640 characters. See Buttons and Quick Replies. |
target | object | Yes | Where and how to send. See Target. |
Target
| Field | Type | Required | Description |
|---|---|---|---|
targetType | string | Yes | Value: instagram or facebook. |
pageId | string | For Facebook | ID of the Facebook Page to send from, from subaccounts. Required when targetType is facebook. |
commentId | string | No | Blotato comment ID. When set, Blotato delivers the message as a private reply to that comment instead of a direct message. |
attachment | object | No | Up to 3 call-to-action buttons pinned under the message. See Buttons and Quick Replies. |
quickReplies | array | No | Up to 13 tappable reply chips shown under the message. See Buttons and Quick Replies. |
responseType | string | No | How the message fits the platform's messaging window: RESPONSE, UPDATE, or MESSAGE_TAG. Default RESPONSE. See Messaging Windows. |
tag | string | No | Required when responseType is MESSAGE_TAG (e.g. HUMAN_AGENT). |
Buttons and Quick Replies
Facebook and Instagram support buttons and quick replies in direct messages. Set target.attachment for buttons, or target.quickReplies for chips. The two are mutually exclusive: a request carrying both is rejected with 422.
For any platform-applied limitations, see:
Buttons
Buttons sit under the message and stay there. Up to 3 buttons are supported.
Instagram Limitation: Instagram only renders buttons in the Instagram mobile app. A recipient reading the conversation on instagram.com in a desktop browser sees the message text with no buttons.
Send an attachment or a URL inside text, not both. A message carrying both leaves the URL in text unclickable on desktop, so a desktop recipient ends up with no working link. For a primarily desktop audience, drop the attachment and put the URL in text.
{
"accountId": "98434",
"recipientId": "1784000000",
"text": "Thanks for reaching out! Pick an option below.",
"target": {
"targetType": "instagram",
"attachment": {
"type": "button",
"buttons": [
{ "type": "web_url", "title": "View pricing", "url": "https://example.com/pricing" },
{ "type": "postback", "title": "Talk to sales", "payload": "SALES" }
]
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Value: button. |
buttons | array | Yes | 1 to 3 buttons. |
Each button has:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | web_url opens a link. postback reports the tap back to you. |
title | string | Yes | Button label, 1 to 20 characters. |
url | string | For web_url | Link the button opens. Starts with https://. |
payload | string | For postback | Value echoed back on tap, 1 to 1000 characters. |
With buttons set, text is required and limited to 640 characters.
Quick Replies
Quick replies are tappable chips offered as canned answers. They disappear once the person taps one or types their own message. Pass 1 to 13.
{
"accountId": "98434",
"recipientId": "1784000000",
"text": "What size do you need?",
"target": {
"targetType": "instagram",
"quickReplies": [
{ "title": "Small", "payload": "SIZE_S" },
{ "title": "Medium", "payload": "SIZE_M" },
{ "title": "Large", "payload": "SIZE_L" }
]
}
}
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Chip label, 1 to 20 characters. |
payload | string | Yes | Value echoed back on tap, 1 to 1000 characters. |
Quick replies require non-empty message text.
Reading a Tap
A quick-reply tap and a postback tap both arrive as the next incoming message carrying payload.selection, but they reach you differently.
Quick replies send a real text message. text holds the chip label, adn Blotato attaches payload.selection alongside it.
{
"id": "msg_def456",
"direction": "incoming",
"text": "Your chip label",
"payload": {
"selection": { "type": "quick-reply", "payload": "The chip payload" }
}
}
Postbacks do not send a text message. Blotato records the tap as an incoming message, sets text to the button label, and attaches payload.selection.
{
"id": "msg_ghi789",
"direction": "incoming",
"text": "Your button label",
"payload": {
"selection": { "type": "postback", "payload": "SALES" }
}
}
| Field | Value | Meaning |
|---|---|---|
selection.type | quick-reply | The person tapped a chip. text is the chip label. |
selection.type | postback | The person tapped a button you attached. text is the button label. |
selection.payload | string or null | The payload received with the tap. A postback is null when the platform webhook supplies no payload. Creating a postback button through this API requires a payload of 1–1000 characters. |
Branch on selection.payload, not on text. Two chips that share a label are distinguishable only by their payload.
A web_url button produces no selection. The link opens and nothing comes back.
Blotato subscribes your account to the postback webhook when you connect it. If you connected your account before buttons were launched, reconnect to start receiving postback events. Quick-reply taps need no reconnect.
Response
Status Code: 201 Created
Returns a Message Object with status queued.
Errors
Send Message returns 201 on success, 422 when the request is rejected, and 429 when you exceed 30 requests per minute.
Messaging is available on every plan, so there is no "not enabled" rejection, and this endpoint does not return 404. A connected account that is missing or expired surfaces after the message is queued, as a failed message.
A 422 means one of:
- The message exceeds the platform's character limit. Instagram allows 1000 bytes, Facebook 2000 characters, and either drops to 640 characters when buttons are set.
- You passed both
attachmentandquickReplies. Send one or the other. - You set buttons or quick replies without message
text. - The messaging window has closed.
- The comment you are replying to is invalid, or it already received a private reply.
- You reached your monthly active-contacts limit (error code 20101).
responseTypeisMESSAGE_TAGand you did not settag.
Message-send failures that happen after the message is queued do not return an error here. The message reaches status failed with an errorCode and errorMessage. See Messaging Errors.
Messaging Windows
The social platform limits who you can message and when. You reply to people who already have a conversation with you, not arbitrary users.
- Standard window: send a
RESPONSEwithin 24 hours of the contact's last message. - Private reply to a comment: set
commentIdon the target to reply once, within 7 days of the comment. - Outside the window: set
responseTypetoMESSAGE_TAGwith an approvedtag(e.g.HUMAN_AGENT) to send a permitted follow-up.
These windows come from the social platform, not Blotato. A message sent outside an allowed window reaches status failed.
Sending a message to a new person also counts toward your monthly active-contacts limit. See Active Contacts.
Conversation Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato conversation ID. |
accountId | string | ID of the connected account this conversation belongs to. |
platform | string | instagram or facebook. |
participants | array | The other people in the conversation. Each has id, name, username, and profileImageUrl, any of which may be null. |
createdAt | string | ISO 8601 timestamp when the conversation started. |
updatedAt | string | ISO 8601 timestamp of the most recent activity. |
Message Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato message ID. |
conversationId | string or null | Blotato ID of the parent conversation. |
platform | string | instagram or facebook. |
direction | string | incoming for messages you receive, outgoing for messages you send. |
senderId | string or null | Social platform (e.g. Instagram) ID of the sender. |
recipientId | string | Social platform (e.g. Instagram) ID of the recipient. |
text | string | Message text. |
payload | object or null | Rich content on the message. See Payload. |
status | string | Message status. See Status Values. |
errorCode | integer or null | Set only when status is failed. See Messaging Errors. |
errorMessage | string or null | Set only when status is failed. |
createdAt | string | ISO 8601 timestamp when the message was created. |
Payload
payload is null on a plain-text message. Otherwise it holds one or more of:
| Field | Type | Description |
|---|---|---|
attachment | object | Buttons you attached to an outgoing message. See Buttons. |
quickReplies | array | Quick-reply chips you attached to an outgoing message. See Quick Replies. |
selection | object | Set on an incoming message where the person tapped a postback button or a quick reply. Holds type (postback or quick-reply) and your payload string. See Reading a Tap. |
Status Values
An outgoing message you send moves through queued, processing, then sent, or failed if it does not go through. An incoming message you receive shows as delivered.
| Status | Meaning |
|---|---|
queued | Accepted and waiting to send. |
processing | Sending to the social platform. |
sent | Handed to the social platform. |
delivered | An incoming message delivered to you. |
failed | Did not send. See errorMessage. |
Rate Limits
| Endpoint | Limit |
|---|---|
GET /conversations | 60 / min |
GET /conversations/:conversationId | 60 / min |
GET /messages | 60 / min |
GET /messages/:messageId | 60 / min |
POST /messages | 30 / min |
DM Automations /v2/dm-automations
A DM automation sends a direct message when someone comments on your post or sends you a message. Blotato supports DM automations on Instagram and Facebook Pages. Twitter/X, TikTok, LinkedIn, Pinterest, Threads, Bluesky, and YouTube are not supported at this time.
Nine endpoints let you manage automations and inspect their activity:
- List DM Automations —
GET /v2/dm-automations - Get DM Automation —
GET /v2/dm-automations/:id - Create DM Automation —
POST /v2/dm-automations - Update DM Automation —
PATCH /v2/dm-automations/:id - Update DM Automation Trigger —
PATCH /v2/dm-automations/:flowId/triggers/:triggerId - Delete DM Automation —
DELETE /v2/dm-automations/:id - List Runs —
GET /v2/dm-automations/:id/runs - List Logs —
GET /v2/dm-automations/:id/logs - Get Analytics —
GET /v2/dm-automations/:id/analytics
For the web app walkthrough, see DM Automations.
Before You Start
Blotato needs permission to read comments and read and send messages on your account.
If you connected your account before comments, messaging, or (for Instagram) follow gating launched, reconnect it so Blotato has the new permissions.
- For Instagram, see Connect Instagram.
- For Facebook, see Connect Facebook.
For Instagram comment triggers, the connected Instagram account must own the post. DM automations do not run on posts where your account appears only as a collaborator. If you co-authored a post, create the automation under the Instagram account that originally published the post.
How an Automation Runs
- Someone comments on your post or sends your account a message.
- Blotato matches the event against every active trigger on every live automation on the account.
- A match starts one run per matching automation. An automation with a comment trigger and a message trigger starts a single run per event.
- If the automation has a follow gate or email gate, Blotato waits for the contact to complete it. On automations published after September 14, 2026, a contact with an email already on file skips the email gate.
- Blotato sends the DM, then calls the webhook if one is configured. On a comment trigger, Blotato also posts the public reply under the comment right after the first DM. See Comment Reply Object.
- The run reaches
completed,failed,expired, orsuperseded.
Every live automation whose trigger matches starts its own run. Two automations matching the same comment both try to answer it, one reply reaches the contact, and the other run fails. Two automations matching the same message both send. Each matching comment also starts a new run, so a contact who comments the keyword twice gets two replies.
A comment trigger answers with a private reply to the comment. A message trigger answers with a standard DM.
Your own comments and the messages your account sends never start a run.
Comments on Instagram collaborator posts do not start a run for the collaborator account. Use the owner account for the automation.
Testing a Comment Trigger
Test from a different Instagram or Facebook account. A comment posted by the same account connected to the automation is skipped, even when its text matches a trigger keyword.
Optional Steps
Set followGate, emailGate, or webhook to extend the run. Blotato runs the steps in a fixed order:
- Follow gate (
followGate, Instagram only). Sends the gate message with a confirm button, waits up to 30 days for a reply, then checks whether the contact follows the account. A contact who does not follow gets the gate message again. - Email gate (
emailGate). Sends the gate message, waits up to 72 hours for a reply, and reads the first email address out of it. A reply holding no email address returns the gate message. A match saves to the contact. On automations published after September 14, 2026, a contact with an email already on file skips the gate. See Email Gate Object. - Your message (
dmMessageplusbuttons). - Webhook (
webhook). Calls your endpoint after the message sends.
A public reply (commentReply) posts under the triggering comment right after the first DM, which is the gate message when the contact gets one. A run started by a DM skips it. See Comment Reply Object.
A run waiting on a gate reaches expired when the contact never answers inside the window, and superseded when a newer run starts waiting on the same contact.
While a run waits on a contact's reply, their next DM resumes the waiting run instead of starting a new run. A button tap never starts a run.
List DM Automations
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /dm-automations
Method: GET
Description
Returns your DM automations, ordered by creation time (most recent first). Use cursor-based pagination. Archived automations do not appear. Every item includes run counts from the last 24 hours and the time it last ran.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum automations to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "flow_abc123",
"accountId": "98434",
"name": "Auto-DM links from comments",
"platform": "instagram",
"target": { "targetType": "instagram" },
"triggers": [
{
"id": "trg_abc123",
"type": "comment-received",
"keywords": ["price", "link"],
"postId": "post_xyz789",
"isActive": true
},
{
"id": "trg_def456",
"type": "message-received",
"keywords": ["price", "link"],
"isActive": true
}
],
"dmMessage": "Thanks for the interest! Tap below for the link.",
"buttons": [],
"isActive": true,
"publishedVersionId": "ver_001",
"createdAt": "2026-08-01T12:00:00Z",
"updatedAt": "2026-08-02T09:30:00Z",
"stats": {
"triggered": 18,
"completed": 16,
"failed": 2,
"lastRunAt": "2026-09-30T14:22:00Z"
}
}
],
"cursor": "eyJz..."
}
| Field | Type | Description |
|---|---|---|
items | array | List of automations. See DM Automation Object. |
items[].stats | object | Run counts from the last 24 hours: triggered, completed, and failed, plus lastRunAt. |
items[].stats.lastRunAt | string or null | ISO 8601 time the automation last ran. Null when it has never run. |
cursor | string | Cursor for the next page. Absent when there are no more automations. |
For all-time totals and failures from the last 7 days, use Get Analytics.
Get DM Automation
Endpoint
URL: /dm-automations/:id
Method: GET
Description
Fetches a single automation by its Blotato ID, including its triggers and message. An archived automation still returns here with isActive: false.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Blotato ID of the automation. |
Response
Status Code: 200 OK
{ "flow": { "id": "flow_abc123", "...": "..." } }
The flow object is a DM Automation Object.
Create DM Automation
Endpoint
URL: /dm-automations
Method: POST
Description
Creates a DM automation. When any of its triggers fires, the automation sends one direct message: text plus up to 3 link buttons. Pass up to 2 triggers in triggers: one comment-received trigger and one message-received trigger. One matching comment or message starts a single run. Optional fields gate the message behind an Instagram follow check, ask for an email address first, or call a webhook after the message sends.
- Set
followGate(Instagram only) to gate the message behind a follow check. - Set
emailGateto gate it behind the contact replying with an email address. - Set
webhookto call an external endpoint once the message sends. - Set
commentReplyto change the public reply posted under the triggering comment. Omit it to turn on the default replies, or passnullto turn it off.
An automation is created as a draft unless you pass isActive: true. Inspect existing flows before creating another. Keep the example inactive until the user requests activation and approves the account, trigger scope, message, and link. Include only the requested triggers and optional steps.
Request Body
{
"accountId": "98434",
"platform": "instagram",
"target": { "targetType": "instagram" },
"name": "Auto-DM links from comments",
"triggers": [
{
"type": "comment-received",
"keywords": ["price", "link"],
"postId": null
},
{
"type": "message-received",
"keywords": ["price", "link"]
}
],
"dmMessage": "Here is the link you requested.",
"buttons": [
{ "type": "url", "title": "Open link", "url": "https://example.com" }
],
"commentReply": {
"variants": [
{ "text": "Sent! Check your inbox and Message Requests." },
{ "text": "Check your DMs for the link!" },
{ "text": "Just sent it to your inbox." }
]
},
"isActive": false
}
Response
Status Code: 201 Created
{ "flow": { "id": "flow_abc123", "isActive": false, "...": "..." } }
Update DM Automation
Endpoint
URL: /dm-automations/:id
Method: PATCH
Description
Updates an automation. Each field present in the patch replaces that field. Omitted fields stay unchanged. triggers replaces the whole trigger set, and [] clears it. Pass null for followGate, emailGate, commentReply, or webhook to remove it.
The connected account, platform, and target are fixed at creation. To run on a different account, create a new automation.
Request Body
The patch is nested under a patch key.
{
"patch": {
"dmMessage": "New reply text",
"buttons": []
}
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | New automation label, 1-60 characters. |
triggers | array | No | Replaces every trigger. Up to 2 triggers, at most one per type. Pass [] to remove every trigger. See Trigger Object. |
dmMessage | string | No | Replaces the message text, 1-640 characters. |
buttons | array | No | Replaces the buttons. Pass [] to remove every button. |
followGate | object or null | No | Replaces the follow gate. Pass null to remove it. Instagram only. See Follow Gate Object. |
emailGate | object or null | No | Replaces the email gate. Pass null to remove it. See Email Gate Object. |
webhook | object or null | No | Replaces the webhook. Pass null to remove it. See Webhook Object. |
commentReply | object or null | No | Replaces the public reply. Pass null to turn it off. See Comment Reply Object. |
isActive | boolean | No | true publishes the automation. false moves it to draft. Omit to keep the current state. |
Content changes to a live automation publish as soon as the request succeeds. Content changes to a draft stay saved until you pass isActive: true. A run already in progress keeps the version it started with.
A live automation needs at least one active trigger. To clear every trigger, pass an empty triggers array and set isActive: false in the same request. To remove one trigger, pass triggers holding the trigger you keep. To update a single trigger without other changes, for example to turn it off, use Update DM Automation Trigger.
Updating an automation's content or triggers reissues its trigger IDs. Read triggers from the response before you call Update DM Automation Trigger.
Response
Status Code: 200 OK
{ "flow": { "id": "flow_abc123", "...": "..." } }
Update DM Automation Trigger
Endpoint
URL: /dm-automations/:flowId/triggers/:triggerId
Method: PATCH
Description
Updates a single trigger on an automation, for example to turn it on or off. The change applies immediately on a live automation, with no republish. The other triggers, the message, and the optional steps stay as they are.
Read the trigger ID from the triggers array of the automation. Updating an automation's content or triggers reissues its trigger IDs, so fetch the automation again before you update a trigger.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
flowId | string | Yes | Blotato ID of the automation. |
triggerId | string | Yes | ID of the trigger, from the automation's triggers array. |
Request Body
The patch is nested under a patch key.
{
"patch": { "isActive": false }
}
| Field | Type | Required | Description |
|---|---|---|---|
isActive | boolean | Yes | true turns the trigger on. false turns it off. |
A live automation needs at least one active trigger. Turning off its last active trigger returns 422 with error code 20303. To stop every trigger, move the automation to draft with Update DM Automation.
A draft accepts any update. Blotato checks the active-trigger rule when you publish.
Response
Status Code: 200 OK
{
"trigger": {
"id": "trg_abc123",
"type": "comment-received",
"keywords": ["price", "link"],
"postId": null,
"isActive": false
}
}
The trigger object is a Trigger Object. A 404 means the automation or the trigger ID was not found.
Delete DM Automation
Endpoint
URL: /dm-automations/:id
Method: DELETE
Description
Archives an automation and stops new runs. Existing runs, including waiting gates, remain able to continue. Archiving does not cancel messages already queued. Archive only when the user requests it.
The archived automation leaves List DM Automations, but Get DM Automation still returns it. Publishing it again with Update DM Automation and isActive: true restores it.
Response
Status Code: 200 OK
Returns the archived DM Automation Object.
List Runs
Endpoint
URL: /dm-automations/:id/runs
Method: GET
Description
Returns the execution runs of one automation, ordered by activity time (most recent first). Use this endpoint to confirm an automation fired and inspect failed runs.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Maximum runs to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
status | string[] | No | Include runs matching any supplied status: running, waiting, completed, expired, superseded, or failed. Omit to include every status. |
since | string | No | Include runs with activity at or after this ISO 8601 timestamp. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "run_abc123",
"contactId": "1784000000",
"platform": "instagram",
"status": "failed",
"error": {
"code": 20102,
"message": "Messaging window has expired",
"action": "Ask the contact to send a new message, then retry.",
"details": { "retryable": false }
},
"createdAt": "2026-08-02T09:30:00Z",
"updatedAt": "2026-08-02T09:30:04Z"
}
],
"cursor": "eyJz..."
}
See Run Object.
List Logs
Endpoint
URL: /dm-automations/:id/logs
Method: GET
Description
Returns logs written as an automation's runs progress, ordered by creation time (most recent first). Pass flowRunId to narrow the response to one run.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
flowRunId | string | No | Include logs belonging to this run. Omit to include logs across every run. |
limit | integer | No | Maximum logs to return (1-250). Default 50. |
cursor | string | No | Cursor from a previous response. Pass it to fetch the next page. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "log_abc123",
"flowRunId": "run_abc123",
"nodeId": "nd_9fJ2",
"level": "info",
"message": "Queued message for send",
"context": { "messageId": "msg_abc123" },
"createdAt": "2026-08-02T09:30:01Z"
}
],
"cursor": "eyJz..."
}
See Log Object.
Get Analytics
Endpoint
URL: /dm-automations/:id/analytics
Method: GET
Description
Returns all-time run totals and the number of recent failures for one automation.
Response
Status Code: 200 OK
{
"analytics": {
"triggered": 412,
"completed": 398,
"failed": 9,
"issues": 3
}
}
| Field | Type | Description |
|---|---|---|
triggered | integer | Runs started by a matching comment or message. |
completed | integer | Runs where every step finished. |
failed | integer | All-time runs ending on an error. |
issues | integer | Runs that failed during the last 7 days. This is a subset of failed. |
Runs still in progress and runs ending as expired or superseded count toward triggered, but not completed or failed. The sum of completed and failed is sometimes lower than triggered.
DM Automation Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato automation ID. |
accountId | string | ID of the connected account the automation runs on. |
name | string | Automation label. |
platform | string | instagram or facebook. |
target | object | See Target. |
triggers | array | Triggers the automation listens for, up to 2. Empty on a draft with no triggers. See Trigger Object. |
dmMessage | string | Message text sent when a trigger fires. |
buttons | array | Link buttons attached to the message. See Button Object. |
followGate | object | Follow gate on the automation. Absent when no follow gate is set. See Follow Gate Object. |
emailGate | object | Email gate on the automation. Absent when no email gate is set. See Email Gate Object. |
webhook | object | Webhook on the automation. Absent when no webhook is set. See Webhook Object. |
commentReply | object | Public reply posted under the triggering comment. Absent when the public reply is off. See Comment Reply Object. |
isActive | boolean | true when the automation is live and listening. |
publishedVersionId | string or null | ID of the published version. null for a draft. |
createdAt | string | ISO 8601 timestamp when the automation was created. |
updatedAt | string | ISO 8601 timestamp of the most recent edit. |
Target
| Field | Type | Required | Description |
|---|---|---|---|
targetType | string | Yes | instagram or facebook. |
pageId | string | For Facebook | ID of the Facebook Page, from subaccounts. Required when targetType is facebook. |
Trigger Object
An automation holds up to 2 triggers: one comment-received trigger and one message-received trigger. Each trigger carries its own keywords, and a comment trigger carries its own postId. One matching comment or message starts a single run.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Read-only | Blotato trigger ID. Present on every trigger Blotato returns. Omit it when you create or update an automation. Pass it to Update DM Automation Trigger. |
type | string | Yes | comment-received or message-received. A comment-received trigger fires on top-level comments only, and skips replies to comments. |
keywords | array | Yes | Words or phrases the comment or message must contain. Pass [] to fire on every comment or text message. A message without text, such as a photo or sticker, never fires. |
postId | string or null | No | Comment triggers only. Blotato ID of the tracked post to match. Do not use the platform's native post ID. null watches every post and reel on the account. |
isActive | boolean | No | false turns this trigger off while the automation stays live. Default true. |
Blotato enforces these rules when an automation goes live and while it stays live:
- At least one active trigger.
- At most one trigger per type.
A draft holds any trigger set, including an empty one. Blotato rejects a request with more than 2 triggers.
Updating an automation's content or triggers reissues its trigger IDs. Read triggers from the response before you update a trigger.
Keyword matching ignores case, matches anywhere in the text, and tolerates line breaks inside a multi-word keyword. For example, price matches both price and pricey. A comment or message fires the automation when it contains any one of the keywords.
The trigger matches a Blotato post ID, not publication origin. List Published Posts and the web post picker list Blotato-published posts only. For an Instagram post published outside Blotato, an incoming comment creates a tracked post record. Retrieve the comment through List Comments, verify its account and native platformPostId, and use its non-null postId for the trigger. The request still needs the connected account and platform containing this post.
If the required Blotato post ID is unavailable, stop and explain the missing ID. Do not replace it with a native ID or widen a single-post request to all posts. Use postId: null with a keyword only when the user approves matching across the account's posts and reels.
Button Object
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | url. Link buttons are the only type buttons accepts. |
title | string | Yes | Button label, up to 20 characters. |
url | string | Yes to publish | http(s) URL the button opens. |
To send quick-reply chips or postback buttons, use Send Message.
Instagram renders buttons in the Instagram mobile app only. A recipient reading the DM on instagram.com in a desktop browser sees the message text with no buttons. To work around this issue, you can add the URL directly to the message text, and Instagram will render it as a clickable link. Set buttons or put a URL inside dmMessage, not both, since a message carrying both leaves the URL unclickable on desktop. For a desktop audience, pass buttons: [] and put the URL in dmMessage. See Instagram Limitations.
Follow Gate Object
Instagram only. Holds dmMessage back until the contact follows the account.
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Gate message text, 1-640 characters. Blotato sends it with a confirm button under it. |
buttonTitle | string | No | Label on the confirm button, up to 20 characters. Default I'm following. |
Blotato sends the gate message, waits up to 30 days for a reply, then reads the contact's follower status. A contact who follows receives dmMessage. A contact who does not receives the gate message again.
- The gate message always goes first. Instagram grants access to follower status once the contact opens a DM thread with the account, so the gate message precedes the check.
- An unknown follower status sends
dmMessage. Instagram withholds follower status for a contact who never granted profile access, and Blotato proceeds rather than blocking them. - A confirmed follow lasts 30 days. The gate message still goes out on every run. Blotato reuses a confirmed follow for 30 days, so a repeat contact's reply passes without a new check. A negative result is never reused.
- The confirm button is a postback button Blotato manages. You set its label only. See Instagram Limitations.
- Any text reply advances the gate. Blotato runs the follower check on the contact's next text DM, whatever it says. A photo, sticker, or voice note does not count. The tap is a shortcut, not a requirement.
- The account needs a button-tap subscription. Blotato subscribes the account at connect time. An account connected before DM automations and follow gating landed does not reliably receive a tap, and runs reach
expired. Reconnect the account to fix it. - Instagram renders the confirm button in the mobile app only. A contact reading on instagram.com in a desktop browser sees the gate message with nothing to tap. Write
messageto ask for a typed reply, for example "Reply FOLLOWING once you have", so a desktop audience still advances.
Email Gate Object
Holds dmMessage back until the contact replies with an email address.
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Gate message text, 1-640 characters. |
Blotato sends the gate message, waits up to 72 hours for a reply, and reads the first email address out of it. A reply holding no email address returns the gate message and Blotato waits again. A match saves to the contact and dmMessage sends.
A contact with an email already on file skips the gate. Blotato sends dmMessage without the gate message. An email lands on file when the contact replies with an address to any email gate on the same connected account.
This applies to automations published after September 14, 2026. An automation published earlier sends the gate message every time until you save it again. Pass its current triggers to Update DM Automation, or click Save and Publish in the web app.
Blotato checks the shape of the address, not whether the mailbox exists. Read a captured address through the Webhook Object.
Comment Reply Object
Public reply posted under the comment which started the run, right after the first DM.
| Field | Type | Required | Description |
|---|---|---|---|
variants | array | Yes | 3 to 6 reply variants, each an object with a text field, for example { "text": "Sent!" }. Fewer or more returns 400. Blotato picks one at random for each comment. Each text holds up to 2,200 characters on Instagram and 8,000 characters on Facebook, counting each {{mention}} as 31 characters, the longest tag it can become. A text of only spaces returns 400. {{mention}} in a text becomes a tag of the commenter. |
Create DM Automation turns on 3 default replies when you omit commentReply: Sent to your DMs! Check Message Requests (top right) and tap Accept 📬, Sent! 📩 Two spots to check: your inbox, and Message Requests (sometimes Hidden Requests too), Sent! 🙂 Not in your inbox? Check Message Requests and tap Accept. Pass null to create the automation without a public reply. Update DM Automation leaves the public reply unchanged when you omit it.
- Comment triggers only. A run started by a DM posts no public reply.
{{mention}}tags the contact. Blotato replaces it with@usernameon Instagram and a profile tag on Facebook. A text without{{mention}}tags nobody, and the contact still gets a notification. An Instagram contact with no username on file gets the reply without the tag.- The reply follows the first DM. With a gate, the gate message is the first DM, so the reply posts before the contact answers the gate.
- No DM, no reply. When the private reply fails, Blotato posts no public reply.
- A failed public reply fails the run. The contact keeps the first DM, and no later message goes out, including
dmMessagebehind a gate, and the webhook is not called. The run reports the comment error, for example error code 20201. - A text needs words besides
{{mention}}. Blotato trims each text. A text of only{{mention}}blocks publishing with error code 20303. - Automations created before public replies launched post no reply until you set
commentReply.
Webhook Object
Endpoint Blotato calls after dmMessage sends.
| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | GET, POST, PUT, PATCH, or DELETE. |
url | string | Yes | Public http(s) endpoint, 1-2048 characters. |
headers | object | No | String keys and string values sent with the request, for example an API key. |
Every method except GET carries a JSON body with Content-Type: application/json. GET carries no body.
{ "email": "them@example.com", "isFollower": true }
| Field | Type | Description |
|---|---|---|
email | string or null | Email address on file for the contact, captured by an email gate. null when Blotato holds none. |
isFollower | boolean or null | Follower status a follow gate last recorded for the contact. null when Blotato never checked. |
Both keys are present on every request except GET, with or without a gate on the automation.
| Rule | Behavior |
|---|---|
| Address | The host must resolve to a public address. Private, loopback, link-local, and cloud metadata ranges return error code 20304. |
| Protocol | http and https only. |
| Redirects | Blotato does not follow them. Point the automation at the final URL. |
| Timeout | 15 seconds. A timeout logs a warning with error code 20305, the run still completes, and Blotato does not retry the request. |
| Response body | Blotato reads the first 16 KB. |
| Error response | A non-2xx status gets logged with its status, and the run still completes. |
| Failure | A blocked address, a DNS failure, or a connection error fails the run with error code 20304. |
| Headers | Redacted from run logs. The URL and body appear in the logs, so send keys in a header, not in the URL. |
This webhook is separate from the webhook publish target, which sends post content to your endpoint at publish time.
Run Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato run ID. Pass it as flowRunId to List Logs. |
contactId | string | Social platform ID of the person who triggered the run. |
platform | string | instagram or facebook. |
status | string | See Run Status Values. |
error | object | Set only when status is failed. Holds code, message, and, when available, action and details with recovery context. |
createdAt | string | ISO 8601 timestamp when the run started. |
updatedAt | string | ISO 8601 timestamp of the most recent run update. |
Run Status Values
| Status | Meaning |
|---|---|
running | Executing a step. |
waiting | Waiting for the DM to settle, or waiting on the contact to answer a gate. |
completed | Every step finished, including the DM. |
expired | The contact never answered a gate inside its window: 30 days for a follow gate, 72 hours for an email gate. A run also expires when its message never settles within 30 minutes. Nothing further sent. |
superseded | A newer run started waiting on the same contact, so this one stopped. |
failed | The run stopped on an error, either before or after the DM went out. Read error. |
Log Object
| Field | Type | Description |
|---|---|---|
id | string | Blotato log ID. |
flowRunId | string | ID of the run this log belongs to. |
nodeId | string or null | ID of the step the log came from. null for run-level entries. |
level | string | info, warning, or error. |
message | string | Description of the step. |
context | object | Step-specific details, for example the message ID. |
createdAt | string | ISO 8601 timestamp when the log was written. |
Platform Rules
Instagram and Facebook set these rules, not Blotato. A message outside an allowed window reaches status failed on the run.
- Comment trigger. Blotato answers with a private reply to the comment. Both platforms allow one private reply per comment, within 7 days of the comment. A comment that already received a private reply, through Blotato or another tool, rejects the second reply.
- Message trigger. Blotato replies within 24 hours of the person's last message.
- No cold outreach. An automation only answers people who comment or message first.
- A reply during a gate continues the run. While a run waits on a contact's answer, their next DM resumes the waiting run instead of starting a new one. A button tap never starts a run.
See Messaging Windows.
Active Contacts
Every DM an automation sends counts toward your monthly active-contacts limit, the same as a message sent through Send Message. Reaching the same person twice in a month counts once.
See Active Contacts.
Errors
| Status | Reason |
|---|---|
404 | The automation was not found. Returned by Get DM Automation, Update DM Automation, Update DM Automation Trigger, and Delete DM Automation. Update DM Automation Trigger also returns it for an unknown trigger ID. An archived automation still returns 200 from Get, Update, and Delete. |
422 | The automation is invalid for publishing (error code 20303), or the connected account is missing (error code 5000). Setting followGate on a facebook automation returns 20303. So does a live automation with no trigger, two triggers of one type, no active trigger, a public reply holding only {{mention}}, a public reply over the platform's comment length, or a public reply with a variable other than {{mention}}. |
500 | Unexpected server error. |
A webhook failure surfaces on the run, not on the request. A blocked address, a DNS failure, or a connection error fails the run with error code 20304. A timeout logs a warning with error code 20305, and the run still completes. See Error Reference.
Rate Limits
| Endpoint | Limit |
|---|---|
GET /dm-automations | 60 / min |
GET /dm-automations/:id | 60 / min |
POST /dm-automations | 30 / min |
PATCH /dm-automations/:id | 30 / min |
PATCH /dm-automations/:flowId/triggers/:triggerId | 30 / min |
DELETE /dm-automations/:id | 30 / min |
GET /dm-automations/:id/runs | 60 / min |
GET /dm-automations/:id/logs | 60 / min |
GET /dm-automations/:id/analytics | 60 / min |
Create Source /v2/source-resolutions-v3
Submit content for extraction and receive a source ID for polling.
Endpoint
POST https://backend.blotato.com/v2/source-resolutions-v3
Rate Limit: 30 requests / minute
Authentication
Include your Blotato API key in the request headers:
blotato-api-key: YOUR_API_KEY
Source Types
| Value | Requires | Description |
|---|---|---|
youtube | url | Extract YouTube transcript (English captions only) |
tiktok | url | Extract TikTok transcript (English captions only) |
article | url | Extract article text from a web page |
pdf | url | Extract text from a PDF |
audio | url | Transcribe audio (mp3, wav, m4a, ogg, flac, aac) |
twitter | url | Extract tweet content |
text | text | Transform raw text content with optional AI instructions |
perplexity-query | text | AI-powered web research query |
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
source.sourceType | string | Yes | One of: youtube, tiktok, article, pdf, audio, twitter, text, perplexity-query |
source.url | string | Required for URL-based types | The URL to extract content from |
source.text | string | Required for text and perplexity-query | Raw text or search query |
customInstructions | string | No | AI instructions to transform extracted content |
Examples
Extract YouTube Transcript
{
"source": {
"sourceType": "youtube",
"url": "https://www.youtube.com/watch?v=VIDEO_ID"
}
}
YouTube and TikTok transcript extraction reads English captions only. A non-English video, or a video with no captions, returns a failed status. For those videos, pass the transcript or a summary using sourceType: "text" instead.
Extract Article with Custom Instructions
{
"source": {
"sourceType": "article",
"url": "https://example.com/article"
},
"customInstructions": "Summarize in 5 bullet points"
}
AI Research Query
{
"source": {
"sourceType": "perplexity-query",
"text": "latest AI trends in social media marketing"
}
}
Transform Raw Text
{
"source": {
"sourceType": "text",
"text": "Your raw content here..."
},
"customInstructions": "Rewrite as a Twitter thread"
}
Response
{
"id": "123e4567-e89b-12d3-a456-426614174000"
}
Use this ID with the Get Source endpoint to retrieve the extracted content.
n8n and Make.com
- In n8n, select Source > Create.
- Save the returned
id. - Use Source > Get to check the saved ID until
statusiscompletedorfailed. - Read
contentaftercompleted, or reportmessageafterfailed.
Follow the n8n polling instructions or the source-to-publication workflow.
For Make, follow the Make setup guide. Inspect the installed module's fields or use the async REST contract. n8n operation labels do not establish Make module labels.
Get Source /v2/source-resolutions-v3/:id
Retrieve extracted content by source ID.
Endpoint
GET https://backend.blotato.com/v2/source-resolutions-v3/:id
Authentication
Include your Blotato API key in the request headers:
blotato-api-key: YOUR_API_KEY
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The source resolution ID (UUID) from Create Source |
Clean Transcript Option
cleanTranscript is not a REST query parameter or an MCP tool argument. The n8n Blotato node's Source > Get operation provides a local Clean Transcript option, enabled by default. It processes the returned content after the API request.
For REST or MCP, retrieve the completed content first, then remove transcript timestamps in your agent or workflow if requested. Do not send cleanTranscript to this endpoint expecting it to change the response.
Response
Processing (poll again)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "processing"
}
Completed
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "completed",
"title": "Video Title",
"content": "Extracted text content...",
"referenceUrl": "https://original-source-url.com"
}
Failed
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "failed",
"message": "Error description"
}
Status Values
| Status | Description |
|---|---|
queued | Source submitted, waiting to process |
processing | Extraction in progress |
completed | Extraction successful, content available |
failed | Extraction failed, check message field |
Polling Pattern
Source extraction is asynchronous. After calling Create Source:
- Wait at least 10 seconds
- Call Get Source with the ID
- If status is
queuedorprocessing, wait and retry - If status is
completed, use thecontentfield - If status is
failed, check themessagefield
n8n and Make.com
In the official Blotato nodes:
- Add a Blotato node
- Select "Source" > "Get"
- Pass in the source ID from "Create Source"
- Add a Wait node of at least 10 seconds between status checks
- The extracted content appears in the response
Visual Templates
Create images and videos using pre-built templates with the Create Visual API endpoint.
How to Use Templates
- Choose a template from the categories below
- Retrieve the template through
blotato_list_design_templatesorGET /v2/videos/templates. - Copy its exact
idintotemplateId. Some IDs are UUIDs and others are paths. Do not shorten a path. - Send a POST request to
/v2/videos/from-templateswithinputs: {}, aprompt, andrender: true.
Example Request
Use the prompt parameter to describe what you want. Set inputs to {}. AI fills in the template inputs automatically.
Use the exact returned template ID. For this quote-card template, use the full path below.
POST https://backend.blotato.com/v2/videos/from-templates
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"templateId": "/base/v2/quote-card/77f65d2b-48cc-4adb-bfbb-5bc86f8c01bd/v1",
"inputs": {},
"prompt": "Create 5 motivational quotes about entrepreneurship",
"render": true
}
LLM-Friendly Reference
For LLM integrations, see API Reference for LLMs for a plain text reference with all endpoints and parameters.
Image Slideshows
For product images, see Product Scene Placement.
Create image slideshows with text overlays. Images uploaded or AI-generated.
| Template | ID | Content input | Output |
|---|---|---|---|
| Image Slideshow with Text Overlays | /base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1 | inputs.slides (objects) | Slideshow |
| Instagram Carousel Slideshow | 53cfec04-2500-41cf-8cc1-ba670d2c341a | inputs.slidePrompts (strings) | Slideshow |
The AI Video with AI Voice template uses inputs.scenes, not either slideshow field. Inspect the selected template's inputs before building a manual request.
Quote Cards
Quote card carousels with various background styles.
| Template | ID | Output |
|---|---|---|
| Quote Card with Monocolor Background | /base/v2/quote-card/77f65d2b-48cc-4adb-bfbb-5bc86f8c01bd/v1 | Slideshow |
| Quote Card with Paper Background and Highlight | /base/v2/quote-card/f941e306-76f7-45da-b3d9-7463af630e91/v1 | Slideshow |
Tweet Cards
Twitter/X-style quote cards with minimal or photo/video backgrounds.
| Template | ID | Output |
|---|---|---|
| Tweet Card with Minimal Style | /base/v2/tweet-card/ba413be6-a840-4e60-8fd6-0066d3b427df/v1 | Slideshow |
| Tweet Card with Photo/Video Background | /base/v2/tweet-card/9714ae5c-7e6b-4878-be4a-4b1ba5d0cd66/v1 | Slideshow |
Tutorial Carousels
Step-by-step tutorial visuals with customizable styling.
| Template | ID | Output |
|---|---|---|
| Tutorial Carousel with Minimalist Flat Style | /base/v2/tutorial-carousel/2491f97b-1b47-4efa-8b96-8c651fa7b3d5/v1 | Slideshow |
| Tutorial Carousel with Monocolor Background | /base/v2/tutorial-carousel/e095104b-e6c5-4a81-a89d-b0df3d7c5baf/v1 | Slideshow |
Images with Text
Combine images and text overlays in various styles.
| Template | ID | Output |
|---|---|---|
| Image Slideshow with Prominent Text | /base/v2/images-with-text/0ddb8655-c3da-43da-9f7d-be1915ca7818/v1 | Slideshow |
| When X then Y Text Slideshow | /base/v2/images-with-text/c9892c3b-fa75-4ade-821a-a50ff8456230/v1 | Video |
| Video of Images and Text with Minimal Style | /base/v2/images-with-text/3ed4bb92-dbfe-45e6-9dc8-605b77f70506/v1 | Video |
Video Editor
Combine and edit video clips with titles, captions, and music.
| Template | ID | Output |
|---|---|---|
| Combine Clips and Apply Basic Edits | /base/v2/combine-clips/c306ae43-1dcc-4f45-ac2b-88e75430ffd8/v1 | Video |
AI Videos
AI-powered video generation with voiceovers and narration.
| Template | ID | Output |
|---|---|---|
| AI Video with AI Voice | /base/v2/ai-story-video/5903fe43-514d-40ee-a060-0d6628c5f8fd/v1 | Video |
| AI Selfie Talking Video with Consistent Character | /base/v2/ai-selfie-video/57f5a565-fd17-458b-be43-4a2d8ccaca75/v1 | Video |
AI Avatar
AI avatar videos with generated B-roll footage.
| Template | ID | Output |
|---|---|---|
| AI Avatar with AI Generated B-roll | /base/v2/ai-avatar-broll/7c26a1cd-d5b3-42da-9c73-2413333873b3/v1 | Video |
AI-Generated Infographics (V1 Legacy)
AI-powered infographic templates that generate single images based on text descriptions. Each template applies a unique visual style to your content.
News and Media
| Template | ID | Output |
|---|---|---|
| TV Wall Infographic | /video-template/013904bf-6b3b-43f4-bb1f-f1964a38c29b | Image |
| Newspaper Infographic | /video-template/07a5b5c5-387c-49e3-86b1-de822cd2dfc7 | Image |
| Breaking News | /video-template/8800be71-52df-4ac7-ac94-df9d8a494d0f | Image |
| Movie Theater Infographic | /video-template/b88c8273-6406-48c6-85e7-096119aefe30 | Image |
Urban and Street
| Template | ID | Output |
|---|---|---|
| Graffiti Mural Infographic | /video-template/3598483b-c148-4276-a800-eede85c1c62f | Image |
| Bus Ad Infographic | /video-template/f9c0e470-9288-4958-8cdd-64772ed93c05 | Image |
| Billboard Infographic | /video-template/76b3b959-bdbe-440d-8428-984219353f18 | Image |
Education
| Template | ID | Output |
|---|---|---|
| Classroom Chalkboard Infographic | /video-template/d9495026-3945-44f6-8b44-07c28c492e6d | Image |
| Whiteboard Infographic | /video-template/ae868019-820d-434c-8fe1-74c9da99129a | Image |
| Chalkboard Infographic | /video-template/fcd64907-b103-46f8-9f75-51b9d1a522f5 | Image |
Outdoor
| Template | ID | Output |
|---|---|---|
| Trail Marker Infographic | /video-template/29ebb2bd-02b7-4317-8bb8-c30eb938e47c | Image |
| Constellation Infographic | /video-template/5307053e-046b-4c9b-b1ca-38725d2ddcdd | Image |
Creative
| Template | ID | Output |
|---|---|---|
| Manga Panel Infographic | /video-template/49c61370-a706-4b82-98f7-62d557d1c66d | Image |
| T-Shirt Infographic | /video-template/476f8920-8749-4ff7-9c91-470d54c3c03e | Image |
| Futuristic Flyer | /video-template/8fa8545e-8955-4a89-a868-cf45023d6cc5 | Image |
| Book Page Infographic | /video-template/f8f1ebe4-a9f5-4ec8-be63-21214656cd4b | Image |
| Single Centered Text Quote | /video-template/9f4e66cd-b784-4c02-b2ce-e6d0765fd4c0 | Slideshow |
Tech
| Template | ID | Output |
|---|---|---|
| Steampunk Infographic | /video-template/7b7104f1-d277-4993-ad3a-e5883c4b776d | Image |
| Top Secret Infographic | /video-template/b8707b58-a106-44af-bb12-e30507e561af | Image |
Historical
| Template | ID | Output |
|---|---|---|
| Egyptian Hieroglyph Infographic | /video-template/a7b0d128-8478-4b34-9647-a0778b6517d0 | Image |
| Cave Painting Infographic | /video-template/82ee75b6-597b-43a8-86bc-e4395e7c9c44 | Image |
Don't See a Template for Your Use Case?
Submit a support ticket and describe the type of visual you need. To submit a ticket, click the orange circle button inside Blotato.
Include the following in your request:
- A description of the visual format you need (e.g., "listicle carousel with numbered items")
- The platform you plan to post on (e.g., Instagram, TikTok, LinkedIn)
- A link to an example of the format, if available
See Also
Create Visual /v2/videos/from-templates
Migrating from the Old API Format
If you are getting this error: body.textToImageModel must be object, body.imageToVideoModel must NOT be valid
Your workflow is using an outdated request format. The old POST /v2/videos/creations endpoint with textToImageModel and imageToVideoModel as string fields no longer works.
Switch to the template system using POST /v2/videos/from-templates:
- Browse available templates at my.blotato.com/videos/new
- In n8n or Make, replace the old node with the Blotato "Create Visual" node
- Select your template from the dropdown (start with a carousel — it renders in seconds)
- Open the Logs to inspect the exact JSON payload each template expects
- Override inputs one by one to customize
For AI story videos, choose the template named "AI Video with AI Voice."
See also: n8n FAQ — textToImageModel and imageToVideoModel
Creating a Visual
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /videos/from-templates
Method: POST
Description
This endpoint creates a new visual (image or video) from a template. Templates define the structure and input parameters for generating visuals like slideshows, quote cards, tweet cards, and more.
You can provide input parameters manually, or use the optional prompt parameter to have AI automatically fill in the template inputs based on your description.
Brand Kit is opt-in. Send a nonempty prompt and useBrandKit: true to include brand context when generating template inputs. An omitted or null brandId uses the primary brand. Without these conditions, include the required brand instructions in your prompt. MCP does not expose the same brand fields. See Brand Kit.
Request
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
templateId | string | ✅ | The ID of the template to use. Get available templates from the /v2/videos/templates endpoint. |
inputs | object | ✅ | Template-specific input parameters. Structure depends on the selected template. Can be an empty object {} if using the prompt parameter. |
isDraft | boolean | ❌ | Save as draft without rendering. Default: false. |
prompt | string | ❌ | Optional natural language prompt to auto-fill template inputs using AI. When provided, AI interprets your description and fills in the inputs automatically. Any manually provided inputs take precedence over AI-generated values. |
render | boolean | ❌ | Whether to render the visual immediately. Default: true. |
title | string | ❌ | A human-readable title for the generated video. |
useBrandKit | boolean | ❌ | Default: false. With a nonempty prompt, includes compiled brand context during template input generation. Requires a configured brand. See Brand Kit. |
brandId | string | null | ❌ | Brand ID for prompt-based generation with useBrandKit enabled. Omitted or null selects the primary brand. |
Getting Available Templates
To list all available templates and their input specifications:
GET https://backend.blotato.com/v2/videos/templates?fields=id,name,description,inputs
The template list includes premade Blotato visual templates only. User-generated visual templates created or edited in the Blotato web app are not available in n8n, Make.com, MCP, or the /v2/videos/templates endpoint. Use a premade Blotato visual template from the dropdown or templates endpoint.
Query Parameters:
| Field | Type | Description |
|---|---|---|
fields | string | Comma-separated list of fields to include. Use id,name,description,inputs to get full template details. |
search | string | Case-insensitive text search in template name or description. Characters are matched literally. Ignored when id is supplied. |
id | string | Optional template ID to get a specific template. |
Inspect inputs without generating a visual
Template lookup is read-only. Do not execute a blank Create Visual request to learn the schema. Generation is a separate operation which consumes credits.
- Call
blotato_list_design_templateswith{"search":"AI Video with AI Voice"}, or send the REST lookup below. - Match the result to the requested output.
- Retain its complete
id. - Read its
inputsspecification for field names, nested types, defaults, allowed values, and limits. - Build the creation request only after confirming those inputs and the user's authorization to generate.
GET /v2/videos/templates?search=AI%20Video%20with%20AI%20Voice&fields=id,name,description,inputs HTTP/1.1
Host: backend.blotato.com
blotato-api-key: YOUR_API_KEY
Search matches text literally, without case sensitivity. For an exact lookup, pass the returned id instead. An empty items array means no matching template was returned. Do not guess another ID or submit an empty templateId.
MCP supplies id, description, and inputs. Do not depend on a title or name field in its result. REST with fields=id,name,description,inputs includes the template's name.
These templates use different input structures:
| Template | Content inputs |
|---|---|
| AI Video with AI Voice | scenes, each with script and mediaSource |
| Image Slideshow with Text Overlays | slides, each with imageSource and optional textOverlay |
| Instagram Carousel Slideshow | slidePrompts, where each entry is an image prompt string |
| Quote Card with Monocolor Background | title and quotes, where each quote is a string |
Changing templateId also requires checking the new template's input schema. slides, slidePrompts, and scenes are not interchangeable.
For an error such as scenes.0: missing object, compare the submitted value at the reported path with the selected template's specification. Increasing wait time does not fix an input-validation error.
Responses
Success Response
Status Code: 201 Created
Visual creation is scheduled on the queue. To check status, poll the Get Visual Status endpoint.
Response Body:
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "queueing"
}
}
Error Responses
Not Found
Status Code: 404 Not Found
{
"message": "Unknown template ID"
}
Too Many Requests
Visual creation has a user-level rate limit of 30 requests / minute.
Status Code: 429 Too many requests
{
"statusCode": 429,
"message": "Rate limit exceeded, retry in 49 seconds"
}
Examples
1. Create a Visual Using AI Prompt (Recommended)
The easiest way to create visuals is using the prompt parameter. AI will interpret your description and fill in the template inputs automatically.
POST https://backend.blotato.com/v2/videos/from-templates HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"templateId": "/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1",
"inputs": {},
"prompt": "Create a 5-slide carousel about productivity tips for remote workers. Use a modern, professional style with blue tones.",
"render": true
}
2. Create a Visual with Manual Inputs
You can also specify inputs manually for full control:
POST https://backend.blotato.com/v2/videos/from-templates HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"templateId": "/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1",
"inputs": {
"slides": [
{
"imageSource": "https://example.com/image1.jpg",
"textOverlay": "Slide 1: Introduction"
},
{
"imageSource": "A serene mountain landscape at sunset",
"textOverlay": "Slide 2: AI-generated image"
}
],
"textPosition": "center",
"aiImageModel": "replicate/recraft-ai/recraft-v3"
},
"render": true
}
3. Combine Prompt with Manual Overrides
You can use prompt for most inputs while manually specifying certain values:
POST https://backend.blotato.com/v2/videos/from-templates HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"templateId": "/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1",
"inputs": {
"textPosition": "bottom",
"textColor": "#FFFFFF"
},
"prompt": "Create a 3-slide motivational carousel about morning routines",
"render": true
}
In this example, AI fills in the slides content, but textPosition and textColor use your manual values.
Available Templates
Browse all templates with parameters and examples in the Visual Templates catalog. You can also use the /v2/videos/templates endpoint to get the current list programmatically. Common templates include:
| Template Type | Description |
|---|---|
| Image Slideshow | Create slideshows from images with text overlays |
| Instagram Carousel Slideshow | AI-generated image carousels from text prompts |
| Quote Card | Generate quote cards with stylized backgrounds |
| Tweet Card | Create visual cards from tweet-style content |
| Tutorial Carousel | Step-by-step tutorial visuals |
| AI Story Video | AI-generated story videos with narration |
| Combine Clips | Merge multiple video clips |
Template Input Types
Templates use various input types:
| Type | Description | Example |
|---|---|---|
text | Plain text string | "Hello world" |
number | Numeric value | 42 |
boolean | True/false | true |
enum | Choice from predefined values | "top" | "center" | "bottom" |
image | Image URL | "https://example.com/image.jpg" |
video | Video URL | "https://example.com/video.mp4" |
color | Hex color code | "#FF5733" |
array | List of items | [{...}, {...}] |
object | Nested object | { "key": "value" } |
Troubleshooting
AI video renders take up to 10-15 minutes. A long render is normal and does not mean the request failed. Keep polling until the status reads done or the response includes error. If error is set, generation has stopped and the status will not change again, even if status is not a final status. If your AI agent reports the render as stuck or failing without an error, nudge it to check the status again before retrying.
If you're still having trouble generating a visual, navigate to https://my.blotato.com/videos/<YOUR_VIDEO_ID> to view and manually edit it.
Polling for Status
After creating a visual, poll the Get Visual Status endpoint to check its status:
GET https://backend.blotato.com/v2/videos/creations/<VIDEO_ID>
Status values (in order):
queueing- Waiting to be processedgenerating-script- AI is generating the scriptscript-ready- Script is ready, generating mediagenerating-media- Media is being generatedmedia-ready- Media is ready, exportingexporting- Final export in progressdone- Complete. UsemediaUrlorimageUrlsfrom the response.creation-from-template-failed- Generation failed
See Get Visual Status for full response details.
Get Visual Status /v2/videos/creations/:id
Check Visual Creation Status
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /videos/creations/:id
Method: GET
Description
Poll this endpoint to check the status of a visual creation. After submitting a request with Create Visual, use the returned id to track its progress. If the response includes error, generation has stopped and the status will not change again, even if status is not a final status.
Request
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The video/visual ID returned by Create Visual |
Response
Status Code: 200 OK
Status Values
| Status | Description |
|---|---|
queueing | Request is queued. Keep polling. |
generating-script | AI is generating the script. Keep polling. |
script-ready | Script is ready, generating media. Keep polling. |
generating-media | Media is being generated. Keep polling. |
media-ready | Media is ready, exporting. Keep polling. |
exporting | Final export in progress. Keep polling. |
done | Complete. mediaUrl and/or imageUrls are available. |
creation-from-template-failed | Creation failed. |
If error is set, stop polling and report the error. For example, a visual can stay at script-ready with an error when AI media generation failed before export.
Response: Done (success)
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "done",
"createdAt": "2025-03-10T15:30:00Z",
"mediaUrl": "https://database.blotato.io/user_1/media/video.mp4",
"imageUrls": ["https://database.blotato.io/user_1/media/slide1.jpg", "https://database.blotato.io/user_1/media/slide2.jpg"]
}
}
mediaUrl: URL of the rendered video. Use this inmediaUrlswhen publishing.imageUrls: Array of image URLs (for slideshows/carousels). Use these inmediaUrlswhen publishing.
Response: In Progress
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "generating-media",
"createdAt": "2025-03-10T15:30:00Z",
"mediaUrl": null,
"imageUrls": null
}
}
Response: Failed
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "creation-from-template-failed",
"createdAt": "2025-03-10T15:30:00Z",
"mediaUrl": null,
"imageUrls": null
}
}
Response: Stopped With Error
{
"item": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "script-ready",
"createdAt": "2025-03-10T15:30:00Z",
"mediaUrl": null,
"imageUrls": null,
"error": "2/5 media failed to generate. The video has been saved as a draft. View the video here: https://my.blotato.com/videos/a1b2c3d4-e5f6-7890-abcd-ef1234567890 to retry generating the media.",
"errorMetadata": {
"numDraftOverlays": 2,
"numAiOverlays": 5
}
}
}
Polling Pattern
1. Create visual: POST /videos/from-templates -> get item.id
2. Poll: GET /videos/creations/{id}
3. If item.error is set: stop and report the error
4. If item.status = "done": use item.mediaUrl or item.imageUrls
5. If item.status = "creation-from-template-failed" or "insufficient-credits": stop and report it
6. If item.status = "draft": report the draft, not a completed render
7. Otherwise: wait at least 15 seconds, go to step 2
How Long It Takes
Most visuals finish within a few minutes. AI video renders take up to 10-15 minutes. A long render is normal and does not mean the request failed. Keep polling until the status reads done or the response includes error. Treat a visual as stopped when error is set, even if status is still script-ready. If the wait exceeds your execution window, save the visual ID and report its current status. Check the existing visual before submitting another create request. Creating another visual starts another job and uses credits.
Example
GET https://backend.blotato.com/v2/videos/creations/a1b2c3d4-e5f6-7890-abcd-ef1234567890 HTTP/1.1
blotato-api-key: YOUR_API_KEY
Error Response
Status Code: 404 Not Found
{
"statusCode": 404,
"message": "Not found"
}
Delete Video /v2/videos/:id
Deleting a single video
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /videos/:id
Method: DELETE
Description
Delete the video. Useful for cleaning up old, unused videos.
Request
Request Params
The request path parameters must contain the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✅ | Video ID |
Responses
Success Response
Status Code: 204 No Content
The video has been deleted successfully.
Response Body:
{
"id": "VIDEO ID",
}
Error Responses
Status Code: 500 Internal server error
{
"statusCode": 500,
"message": "Something went wrong"
}
Scheduled Posts /v2/schedules
Managing Scheduled Posts
Scheduled posts are created via Publish Post using scheduledTime or useNextFreeSlot. These endpoints let you list, inspect, update, and delete scheduled posts before they publish.
To manage the recurring time slots themselves (the calendar grid), see Weekly posting schedule.
List Scheduled Posts
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /schedules
Method: GET
Description
Returns all scheduled posts for the current user. Only future posts are returned, ordered by scheduled time (ascending). Supports cursor-based pagination.
The web app does not have a built-in calendar filter for one brand, account, or page. To build a custom filtered calendar, list scheduled posts with this endpoint, then filter the returned items by account.id, account.subaccountId, account.subId, or account.subaccountName.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Number of items per page. Min: 1, Max: 50. Default: 20. |
cursor | string | No | Pagination cursor from a previous response. |
Response
Status Code: 200 OK
{
"items": [
{
"id": "sch_abc123",
"scheduledAt": "2026-04-01T14:00:00.000Z",
"account": {
"id": "98432",
"name": "Jane Smith",
"username": "janesmith",
"profileImageUrl": "https://...",
"subaccountId": null,
"subId": null,
"subaccountName": null
},
"draft": {
"accountId": "98432",
"content": {
"text": "Scheduled post content",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
],
"count": "12",
"cursor": "eyJzY2hlZHVsZWRBd..."
}
| Field | Type | Description |
|---|---|---|
items | array | List of scheduled posts |
items[].id | string | Schedule ID. Use this for get, update, and delete operations. |
items[].scheduledAt | string | ISO 8601 UTC timestamp for when the post will publish. |
items[].account | object or null | The target social account. Null if the account was disconnected. |
items[].draft | object | The post payload. Same structure as the post object in Publish Post. |
count | string | Total number of future scheduled posts. |
cursor | string | Pagination cursor. Pass this as the cursor query parameter to fetch the next page. Absent when there are no more pages. |
Example
GET https://backend.blotato.com/v2/schedules?limit=10 HTTP/1.1
blotato-api-key: YOUR_API_KEY
With pagination:
GET https://backend.blotato.com/v2/schedules?limit=10&cursor=eyJzY2hlZHVsZWRBd... HTTP/1.1
blotato-api-key: YOUR_API_KEY
Get Scheduled Post
Endpoint
URL: /schedules/:id
Method: GET
Description
Returns a single scheduled post by ID.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Schedule ID from the List Scheduled Posts endpoint. |
Response
Status Code: 200 OK
{
"schedule": {
"id": "sch_abc123",
"scheduledAt": "2026-04-01T14:00:00.000Z",
"account": {
"id": "98432",
"name": "Jane Smith",
"username": "janesmith",
"profileImageUrl": "https://...",
"subaccountId": null,
"subId": null,
"subaccountName": null
},
"draft": {
"accountId": "98432",
"content": {
"text": "Scheduled post content",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
}
Returns 404 if the schedule does not exist or belongs to another user.
Update Scheduled Post
Endpoint
URL: /schedules/:id
Method: PATCH
Description
Update a scheduled post's content, scheduled time, or both. At least one field is required. The scheduled time must be in the future.
When the scheduled time changes, the publishing job is re-queued for the new time.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Schedule ID from the List Scheduled Posts endpoint. |
Request Body
{
"patch": {
"scheduledTime": "2026-04-05T10:00:00Z",
"draft": {
"accountId": "98432",
"content": {
"text": "Updated post content",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
patch.scheduledTime | string | No | New ISO 8601 timestamp. Must be in the future. |
patch.draft | object | No | Updated post payload. Same structure as the post object in Publish Post. When provided, send the full object -- partial updates are not supported. |
Response
Status Code: 204 No Content
Errors
| Status | Reason |
|---|---|
404 | Schedule not found |
422 | Empty patch, invalid date, or scheduled time is in the past |
Examples
Reschedule to a new time
PATCH https://backend.blotato.com/v2/schedules/sch_abc123 HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"patch": {
"scheduledTime": "2026-04-05T10:00:00Z"
}
}
Update the post text
PATCH https://backend.blotato.com/v2/schedules/sch_abc123 HTTP/1.1
Content-Type: application/json
blotato-api-key: YOUR_API_KEY
{
"patch": {
"draft": {
"accountId": "98432",
"content": {
"text": "New text for this scheduled post",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
}
Reschedule to the next available slot
The update endpoint does not accept useNextFreeSlot. To move a post to the next available slot, first call Find Next Available Slot, then pass the returned time as scheduledTime:
1. POST /v2/schedule/slots/next-available
Body: { "platform": "twitter", "accountId": "98432" }
Response: { "slot": { "slotId": "slot_1", "slotTime": "2026-04-02T09:00:00Z" } }
2. PATCH /v2/schedules/sch_abc123
Body: { "patch": { "scheduledTime": "2026-04-02T09:00:00Z" } }
Delete Scheduled Post
Endpoint
URL: /schedules/:id
Method: DELETE
Description
Delete a scheduled post and cancel its publishing job. This action cannot be undone.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Schedule ID from the List Scheduled Posts endpoint. |
Response
Status Code: 204 No Content
Errors
| Status | Reason |
|---|---|
404 | The schedule was not found, does not belong to your account, or is no longer a future scheduled post. |
Example
DELETE https://backend.blotato.com/v2/schedules/sch_abc123 HTTP/1.1
blotato-api-key: YOUR_API_KEY
Schedule Slots
Schedule slots define the recurring time windows in your content calendar. When you publish a post with useNextFreeSlot: true, Blotato picks the next open slot matching the target platform and queues the post at that time.
To manage the posts queued in those slots, see Schedules.
How Slots and Schedules Work Together
- Slots define your posting cadence -- for example, "every Monday at 9:00 AM UTC for Twitter."
- When you publish a post with
useNextFreeSlot: true(see Publish Post), Blotato finds the next slot that matches the target platform and account, and schedules the post at that time. - A slot is "occupied" when a scheduled post is already queued at that time. The next call to
useNextFreeSlotskips occupied slots and picks the next open one. - You manage what is queued (the schedules) and when things are queued (the slots) separately.
List Slots
Endpoint
Base URL: https://backend.blotato.com/v2
URL: /schedule/slots
Method: GET
Description
Returns all scheduling slots for the current user.
Response
Status Code: 200 OK
{
"items": [
{
"id": "slot_1",
"hour": 9,
"minute": 0,
"day": "monday",
"selectedTargets": [
{
"platform": "twitter",
"accountId": "98432",
"subaccountId": null
}
]
},
{
"id": "slot_2",
"hour": 14,
"minute": 30,
"day": "wednesday",
"selectedTargets": [
{
"platform": "instagram",
"accountId": "98434",
"subaccountId": null
},
{
"platform": "linkedin",
"accountId": "98435",
"subaccountId": null
}
]
}
]
}
| Field | Type | Description |
|---|---|---|
items[].id | string | Slot ID |
items[].hour | integer | Hour in UTC (0-23) |
items[].minute | integer | Minute (0-59) |
items[].day | string | Day of week: monday, tuesday, wednesday, thursday, friday, saturday, sunday |
items[].selectedTargets | array | Platforms and accounts this slot applies to |
items[].selectedTargets[].platform | string | Platform name |
items[].selectedTargets[].accountId | string or null | Account ID. Null means the slot applies to all accounts on that platform. |
items[].selectedTargets[].subaccountId | string or null | Subaccount ID (for Facebook Pages / LinkedIn Company Pages). |
Create Slots
Endpoint
URL: /schedule/slots
Method: POST
Description
Create one or more scheduling slots. Each slot defines a day, time (in UTC), and which platforms/accounts it applies to. Returns an error if a slot at the same day and time already exists.
Request Body
{
"slots": [
{
"hour": 9,
"minute": 0,
"day": "monday",
"selectedTargets": [
{
"platform": "twitter",
"accountId": "98432",
"subaccountId": null
}
]
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
slots | array | Yes | Array of slots to create |
slots[].hour | integer | Yes | Hour in UTC (0-23) |
slots[].minute | integer | Yes | Minute (0-59) |
slots[].day | string | Yes | Day of week (e.g., monday) |
slots[].selectedTargets | array | Yes | Platforms and accounts. Set accountId to null for a slot that applies to all accounts on that platform. |
Response
Status Code: 201 Created
Returns the created slots with their generated IDs.
Update Slot Targets
Endpoint
URL: /schedule/slots/:id
Method: PATCH
Description
Replace the selected targets for a slot. Send the full list of targets -- this is a full replacement, not a partial update.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Slot ID |
Request Body
{
"patch": {
"selectedTargets": [
{
"platform": "twitter",
"accountId": "98432",
"subaccountId": null
},
{
"platform": "instagram",
"accountId": "98434",
"subaccountId": null
}
]
}
}
Response
Status Code: 204 No Content
Delete Slot
Endpoint
URL: /schedules/slots/:id
Method: DELETE
Description
Delete a scheduling slot. If future posts still reference this slot, deletion fails. Do not cancel queued posts automatically. Ask whether to keep the slot, reschedule the posts, or cancel them. Obtain authorization before changing or deleting the affected schedules. Changing a schedule's time clears its slot association, so an authorized reschedule preserves the post while freeing the slot. See Schedules.
Past scheduled posts linked to this slot are cleaned up automatically.
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Slot ID |
Response
Status Code: 204 No Content
Errors
| Status | Reason |
|---|---|
400 | Slot has future scheduled content. Preserve the posts until the user chooses to keep, reschedule, or cancel them. |
Find Next Available Slot
Endpoint
URL: /schedule/slots/next-available
Method: POST
Description
Find the next available (unoccupied) slot for a given platform and account. Returns the slot ID and the UTC time of the next open slot.
Use this when you want to reschedule a post to the next free slot via the Update Schedule endpoint, since that endpoint accepts scheduledTime but not useNextFreeSlot.
Request Body
{
"platform": "twitter",
"accountId": "98432",
"subaccountId": null
}
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | Yes | Platform name |
accountId | string | No | Account ID. Omit to match slots for all accounts on the platform. |
subaccountId | string | No | Subaccount ID for Facebook Pages / LinkedIn Company Pages. |
Response
Status Code: 201 Created
{
"slot": {
"slotId": "slot_1",
"slotTime": "2026-04-02T09:00:00Z"
}
}
| Field | Type | Description |
|---|---|---|
slot.slotId | string | The slot that was matched |
slot.slotTime | string | ISO 8601 UTC time of the next open occurrence of this slot |
Returns 400 if no slots are configured for the given platform/account.
Instagram: API and MCP publishing
Instagram publishing requires an image or video. Use a connected Instagram account from account lookup. A caption alone is insufficient.
Fields
| Field | Use |
|---|---|
mediaType | Optional reel or story. Choose the format requested by the user. |
collaborators | Optional array of Instagram usernames without @. |
altText | Optional image description. |
coverImageUrl | Optional public Reel cover URL. |
shareToFeed | Optional boolean for also sharing a Reel to the main feed. |
audioName | Optional name for the Reel's original audio. |
trial | Optional trial Reel settings. Read the publish schema before setting graduationStrategy. |
firstComment | Optional first comment after publishing. Stories do not support it. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Use a single image, a video, or multiple media URLs for a carousel. For a Reel, check the export guidance and automatic-conversion limits. Videos longer than 120 seconds must already satisfy requirements if cropping or conversion would otherwise be needed.
Read Instagram media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "instagram",
"text": "A caption for your Reel.",
"mediaUrls": [
"https://example.com/video.mp4"
],
"mediaType": "reel"
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "instagram",
"text": "A caption for your Reel.",
"mediaUrls": [
"https://example.com/video.mp4"
]
},
"target": {
"targetType": "instagram",
"mediaType": "reel"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
shareToFeed affects Reels. It does not populate the comments inbox or change image posts. Comments, DMs, and analytics have their own sync behavior.
See Instagram account guide, platform help, and the Publish Post reference for options and examples.
Facebook: API and MCP publishing
Choose a connected Facebook Page. Publishing to personal Facebook profiles is not supported. Get pageId from the account's subaccounts.
Fields
| Field | Use |
|---|---|
pageId | Required Facebook Page ID. |
mediaType | Optional reel or story for the media format. |
link | Optional URL for a link preview. |
firstComment | Optional first comment after publishing. Stories do not support it. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Publish text or image posts to the Page feed. Videos publish as Reels or Stories. A Story requires media. See the Facebook media section for duration and conversion requirements.
Read Facebook media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "facebook",
"text": "A post for your Facebook Page.",
"mediaUrls": [],
"pageId": "PAGE_ID_FROM_LOOKUP"
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "facebook",
"text": "A post for your Facebook Page.",
"mediaUrls": []
},
"target": {
"targetType": "facebook",
"pageId": "PAGE_ID_FROM_LOOKUP"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
Select the Page requested by the user when the account has several Pages. A connected personal Facebook account is the authorization account, rather than the posting destination.
See Facebook account guide, platform help, and the Publish Post reference for options and examples.
TikTok: API and MCP publishing
TikTok requires media, a privacy setting, and 6 boolean declarations. Set these from the user's intended privacy, interaction, brand, and AI-content choices. The example uses SELF_ONLY.
Fields
| Field | Use |
|---|---|
privacyLevel | Required: SELF_ONLY, PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, or FOLLOWER_OF_CREATOR. |
disabledComments, disabledDuet, disabledStitch | Required booleans for interaction settings. |
isBrandedContent, isYourBrand, isAiGenerated | Required booleans describing the content. |
title | Optional image-post title. |
autoAddMusic | Optional music setting for image posts. |
isDraft | Optional draft submission instead of direct publication. |
imageCoverIndex, videoCoverTimestamp | Optional cover selection. Read the schema for units and valid values. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Use one video or an image post. Do not put multiple videos in one post. Check media dimensions and conversion requirements before publishing.
Read TikTok media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "tiktok",
"text": "A caption for your TikTok video.",
"mediaUrls": [
"https://example.com/video.mp4"
],
"privacyLevel": "SELF_ONLY",
"disabledComments": false,
"disabledDuet": false,
"disabledStitch": false,
"isBrandedContent": false,
"isYourBrand": false,
"isAiGenerated": false
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "tiktok",
"text": "A caption for your TikTok video.",
"mediaUrls": [
"https://example.com/video.mp4"
]
},
"target": {
"targetType": "tiktok",
"privacyLevel": "SELF_ONLY",
"disabledComments": false,
"disabledDuet": false,
"disabledStitch": false,
"isBrandedContent": false,
"isYourBrand": false,
"isAiGenerated": false
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
Starter permits posting to 3 distinct TikTok accounts during a rolling 24-hour window. This counts posting destinations, rather than connections. A TikTok draft still needs completion in TikTok. Report draft delivery separately from a public post.
See TikTok account guide, platform help, and the Publish Post reference for options and examples.
YouTube: API and MCP publishing
Use a connected YouTube account and a video URL. Provide title, privacyStatus, and shouldNotifySubscribers. The example uses an unlisted video.
Fields
| Field | Use |
|---|---|
title | Required title, up to 100 characters. Do not include < or >. |
privacyStatus | Required: private, public, or unlisted. |
shouldNotifySubscribers | Required boolean. |
isMadeForKids | Optional audience declaration. |
containsSyntheticMedia | Optional synthetic-media declaration. |
thumbnailUrl | Optional public custom-thumbnail URL. Account verification requirements apply. |
playlistIds | Optional array of up to 5 playlist IDs from subaccounts. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Use a video URL in mediaUrls. The text becomes the description. This publish operation does not create channel banners, profile pictures, or YouTube community image posts.
Read YouTube media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "youtube",
"text": "Your video description.",
"mediaUrls": [
"https://example.com/video.mp4"
],
"title": "Your video title",
"privacyStatus": "unlisted",
"shouldNotifySubscribers": false
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "youtube",
"text": "Your video description.",
"mediaUrls": [
"https://example.com/video.mp4"
]
},
"target": {
"targetType": "youtube",
"title": "Your video title",
"privacyStatus": "unlisted",
"shouldNotifySubscribers": false
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
For playlist selection, fetch the account's subaccounts. Custom thumbnails require the supported account verification state. A scheduled Blotato post and an unlisted YouTube video are different outcomes.
See YouTube account guide, platform help, and the Publish Post reference for options and examples.
LinkedIn: API and MCP publishing
Use the connected LinkedIn accountId. Omit pageId for the personal profile. For a company Page, choose pageId from the account's subaccounts.
Fields
| Field | Use |
|---|---|
pageId | Optional LinkedIn company Page ID. Omit for the personal profile. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Publish text, a single image, a video, or an image carousel. For carousels, Blotato builds a LinkedIn Document from the image URLs. Read the media requirements before submitting a video.
Read LinkedIn media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "linkedin",
"text": "A post for your LinkedIn personal profile.",
"mediaUrls": []
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "linkedin",
"text": "A post for your LinkedIn personal profile.",
"mediaUrls": []
},
"target": {
"targetType": "linkedin"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
Do not add a company Page ID unless the user selects the Page. The example below publishes to the personal profile. LinkedIn analytics availability differs from publishing support. See the analytics guide.
See LinkedIn account guide, platform help, and the Publish Post reference for options and examples.
Pinterest: API and MCP publishing
Call blotato_list_pinterest_boards with the Pinterest accountId. Use the selected board's id as boardId. REST lookup: GET /v2/social/pinterest/boards?accountId=....
Fields
| Field | Use |
|---|---|
boardId | Required board ID from the board lookup. |
title | Optional title, up to 100 characters. |
altText | Optional image description, up to 500 characters. |
link | Optional destination URL, up to 2,048 characters. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Use an image, a video, or 2–5 images for a carousel. A video Pin contains one video. The publisher rejects more than 5 media items.
Read Pinterest media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "pinterest",
"text": "A description for your Pin.",
"mediaUrls": [
"https://example.com/image.jpg"
],
"boardId": "BOARD_ID_FROM_LOOKUP"
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "pinterest",
"text": "A description for your Pin.",
"mediaUrls": [
"https://example.com/image.jpg"
]
},
"target": {
"targetType": "pinterest",
"boardId": "BOARD_ID_FROM_LOOKUP"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
Pinterest account eligibility and connection requirements apply before publishing. Read the connection troubleshooting page if the account is blocked from API publishing.
See Pinterest account guide, platform help, and the Publish Post reference for options and examples.
X (Twitter): API and MCP publishing
Use twitter as the platform value, including when the user calls the service X. No extra target identifier is required after selecting accountId.
Fields
| Field | Use |
|---|---|
additionalPosts | Optional thread posts, each with text and mediaUrls. For REST, put this array inside post.content, outside post.target. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Publish text, images, or a video. For a thread, use the main post plus additionalPosts. Validate each post's media and text rather than treating the thread as one caption.
Read X (Twitter) media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "twitter",
"text": "A post for X.",
"mediaUrls": []
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "twitter",
"text": "A post for X.",
"mediaUrls": []
},
"target": {
"targetType": "twitter"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
Account-specific text limits and platform errors still apply. Follow the X FAQ for account questions and the returned validation message for a rejected post.
See X (Twitter) account guide, platform help, and the Publish Post reference for options and examples.
Threads: API and MCP publishing
Use threads as the platform value. No extra target identifier is required after selecting accountId.
Fields
| Field | Use |
|---|---|
replyControl | Optional: everyone, accounts_you_follow, or mentioned_only. |
additionalPosts | Optional thread posts, each with text and mediaUrls. For REST, place this in post.content. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Each post accepts text, one image, or one video. Multiple media URLs in a single Threads post fail. To share several images, create a thread with one image per post using additionalPosts.
Read Threads media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "threads",
"text": "A post for Threads.",
"mediaUrls": []
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "threads",
"text": "A post for Threads.",
"mediaUrls": []
},
"target": {
"targetType": "threads"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
A Threads thread and a media carousel are different structures. Use one media item per post even if a generic media schema allows larger arrays.
See Threads account guide, platform help, and the Publish Post reference for options and examples.
Bluesky: API and MCP publishing
Use bluesky as the platform value. No extra target identifier is required after selecting accountId.
Fields
| Field | Use |
|---|---|
additionalPosts | Optional thread posts, each with text and mediaUrls. For REST, place this in post.content. |
For MCP, pass platform-specific fields alongside accountId, platform, text, and mediaUrls. For REST, platform-specific target fields belong inside post.target. Thread content belongs inside post.content.additionalPosts.
Media and formats
Publish text, up to 4 images, or one video. Blotato waits for Bluesky video processing during publication. Follow the video URL format requirements in the media reference.
Read Bluesky media requirements and upload and conversion rules. Public media URLs go directly in mediaUrls. No upload step required.
MCP example
Call blotato_create_post with the following shape. Replace lookup IDs and example media URLs with returned IDs and your media. Adjust the example's settings to the user's request.
{
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"platform": "bluesky",
"text": "A post for Bluesky.",
"mediaUrls": []
}
REST example
Send this JSON to POST https://backend.blotato.com/v2/posts with your blotato-api-key header.
{
"post": {
"accountId": "ACCOUNT_ID_FROM_LOOKUP",
"content": {
"platform": "bluesky",
"text": "A post for Bluesky.",
"mediaUrls": []
},
"target": {
"targetType": "bluesky"
}
}
}
Verify the result
- Save the returned
postSubmissionId. - If processing continues, use
blotato_get_post_statusorGET /v2/posts/:postSubmissionId. - Report the returned status and public URL when supplied.
For scheduling, add scheduledTime or useNextFreeSlot as an MCP argument or a REST top-level sibling of post. See Scheduling and completion rules.
Limits and troubleshooting
A video submission is not finished until publishing completes. Keep the submission ID and use the status lookup if the MCP create call returns processing status.
See Bluesky account guide, platform help, and the Publish Post reference for options and examples.
Async Workflows
Publishing, source extraction, and visual generation use the Submit → Poll → Result pattern. Read the completion rules for the exact operation. For task instructions using MCP, start with Agent workflows.
System Prompt for Agents
You can use the following snippet to instruct your AI agent on how to interact with Blotato:
Blotato API Protocol: All creation operations (posts, videos, sources) are async.
- Call the
CREATEendpoint. Record the ID from the 201 response (idfor sources,item.idfor videos,postSubmissionIdfor posts). A scheduled post also returnsscheduledTime, the resolved UTC publish time.- Check the
GETendpoint at least 10 seconds apart for posts and sources, and at least 15 seconds apart for visuals.- Continue polling while status is processing (see status values below).
- Stop on a terminal result. Report success only for the operation's success state, not for a failure or draft.
- Set a waiting limit. Preserve the operation ID if processing remains unfinished. Do not submit a duplicate write because a poll failed or time elapsed.
Terminal Status Values by Operation:
- Sources:
completed(success) orfailed- Videos:
done(success),creation-from-template-failed,insufficient-credits, or any response withitem.error. Adraftis not a rendered result.- Posts:
published(success),failed, orscheduledfor a future publication. Stop immediate polling after a scheduled result.All Video Status Values (in order):
queueing->generating-script->script-ready->generating-media->media-ready->exporting->doneAlways fetch accounts first:
GET /v2/users/me/accountsto getaccountIdfor publishing. To getpageIdfor Facebook/LinkedIn orplaylistIdsfor YouTube, also fetchGET /v2/users/me/accounts/{accountId}/subaccounts.For social platforms, set
content.platformandtarget.targetTypeto the same value (e.g., both"twitter"). The REST webhook target usesotherwithwebhook.Content Calendar:
GET /v2/schedulesto list scheduled posts.PATCH /v2/schedules/:idto update content or time.DELETE /v2/schedules/:idto cancel.GET /v2/schedule/slotsfor recurring time slots.Full reference: API reference for agents.
1. Create Source -> Get Source
Goal: Research a topic or extract content from a URL so Blotato can generate related visuals.
Endpoints:
- Create:
POST /v2/source-resolutions-v3 - Poll:
GET /v2/source-resolutions-v3/:id
Source Types:
youtube,tiktok,article,pdf,audio,twitter- Extract content from a URL (each type requires aurlfield)text- Transform raw text content with optional AI instructionsperplexity-query- AI-powered web research on any topic (requires atextfield)
sequenceDiagram
participant Agent
participant API
Note over Agent: 1. Submit Source (URL, Text, or Query)
Agent->>API: POST /v2/source-resolutions-v3<br/>{ source: { sourceType: "...", ... } }
API-->>Agent: 201 Created { id: "src_123" }
Note over Agent: 2. Poll for Extraction
loop At least 10 seconds between checks
Agent->>API: GET /v2/source-resolutions-v3/src_123
API-->>Agent: { status: "processing" }
Note over Agent: Wait...
end
Note over Agent: 3. Receive Result
API-->>Agent: { status: "completed", content: "Extracted text...", title: "..." }
Example Payloads
From YouTube URL:
{
"source": {
"sourceType": "youtube",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}
}
From AI Research Query (use this for agents to research topics):
{
"source": {
"sourceType": "perplexity-query",
"text": "latest trends in AI-generated content for social media"
}
}
From Text with Custom Instructions:
{
"source": {
"sourceType": "text",
"text": "Your raw content here..."
},
"customInstructions": "Summarize in 5 bullet points for Instagram carousel"
}
2. Create Visual -> Get Visual
Goal: Generate a video or image from a template.
Endpoints:
- Create:
POST /v2/videos/from-templates - Poll:
GET /v2/videos/creations/:id - Templates:
GET /v2/videos/templates?fields=id,name,description,inputs
Discovering Templates
If you don't have a specific template ID, retrieve available templates:
GET https://backend.blotato.com/v2/videos/templates?fields=id,name,description,inputs&search=carousel
Choose the template for the requested output. An image carousel, a narrated video, and a clip compilation use different templates and input structures. Inspect the selected template's inputs before generating.
Visual Generation Flow
sequenceDiagram
participant Agent
participant API
Note over Agent: 0. (Optional) Discover Templates
Agent->>API: GET /v2/videos/templates
API-->>Agent: List of templates with IDs
Note over Agent: 1. Submit Generation Request
Agent->>API: POST /v2/videos/from-templates<br/>{ templateId: "...", inputs: {...}, prompt: "..." }
API-->>Agent: 201 Created { item: { id: "vid_456", status: "queueing" } }
Note over Agent: 2. Poll for Rendering
loop At least 15 seconds between checks
Agent->>API: GET /v2/videos/creations/vid_456
API-->>Agent: { item: { status: "generating-media" } }
Note over Agent: Wait...
end
Note over Agent: 3. Receive Media URLs
API-->>Agent: { item: { status: "done", mediaUrl: "https://...", imageUrls: [...] } }
Example Payload (with AI Prompt)
{
"templateId": "/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1",
"inputs": {},
"prompt": "Create a 5-slide carousel about productivity tips",
"render": true
}
Example Payload (with Manual Inputs)
Replace the example image URLs with the user's accessible media URLs before submitting. These URLs illustrate the request structure, not content to publish.
{
"templateId": "/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1",
"inputs": {
"slides": [
{
"imageSource": "https://example.com/slide-1.jpg",
"textOverlay": "Introduction"
},
{
"imageSource": "https://example.com/slide-2.jpg",
"textOverlay": "Next step"
}
]
},
"render": true
}
3. Create Post -> Get Post
Goal: Publish content to a social platform.
Endpoints:
- Create:
POST /v2/posts - Poll:
GET /v2/posts/:postSubmissionId - Account Lookup:
GET /v2/users/me/accounts(docs) - Subaccounts (for pageId):
GET /v2/users/me/accounts/:accountId/subaccounts(docs)
n8n / Make.com users: Check the operations in your installed integration. If it exposes Get Post, pass the original
postSubmissionId. Otherwise, use an HTTP request toGET /v2/posts/{postSubmissionId}with your Blotato credential. Do not assume all integration versions expose the same operations.
[!IMPORTANT] Prerequisites:
accountId: Get this fromGET /v2/users/me/accounts. Always fetch the user's accounts before publishing. See Accounts reference.pageId: Required for Facebook Pages and LinkedIn company Pages. Omit it for a LinkedIn personal-profile post. Get it fromGET /v2/users/me/accounts/{accountId}/subaccounts. See How to Get the Right IDs.mediaUrls: Use existing accessible media URLs, ormediaUrlandimageUrlsfrom an authorized visual-generation request. No upload step required for these URLs. Do not generate new media for a request to publish an existing file. Text-only posts omit media when the selected platform supports them.content.platformandtarget.targetType: For social platforms, set both to the same value (e.g., both"twitter").
Step 0: Fetch Available Accounts (Always Do This First)
GET https://backend.blotato.com/v2/users/me/accounts
Response:
{
"items": [
{ "id": "98432", "platform": "twitter", "fullname": "Jane Smith", "username": "janesmith" }
]
}
For a Facebook Page or LinkedIn company Page, fetch subaccounts and select the requested pageId. Omit pageId for a LinkedIn personal profile. For YouTube, fetch subaccounts only when playlist placement is requested:
GET https://backend.blotato.com/v2/users/me/accounts/{accountId}/subaccounts
See Accounts reference for full details.
Publish Flow
sequenceDiagram
participant Agent
participant API
Note over Agent: 0. Fetch User Accounts
Agent->>API: GET /v2/users/me/accounts
API-->>Agent: List of accounts with IDs
Note over Agent: 1. Submit Post
Agent->>API: POST /v2/posts<br/>{ post: { accountId, content, target } }
API-->>Agent: 201 Created { postSubmissionId: "sub_789" }
Note over Agent: 2. Poll for Publishing
loop At least 10 seconds between checks
Agent->>API: GET /v2/posts/sub_789
API-->>Agent: { status: "in-progress" }
Note over Agent: Wait...
end
Note over Agent: 3. Success
API-->>Agent: { status: "published", publicUrl: "https://twitter.com/..." }
Example Payload
{
"post": {
"accountId": "98432",
"content": {
"text": "Hello world!",
"mediaUrls": ["https://database.blotato.io/user_1/media/vid_456.mp4"],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
Get accountId from GET /v2/users/me/accounts. For social platforms, set content.platform and target.targetType to the same value.
To schedule instead of publishing immediately, add useNextFreeSlot or scheduledTime as a top-level field (sibling of post, not inside it). See Publish Post for details.
Complete End-to-End Workflow (Recommended for AI Agents)
This is the standard content creation sequence: research topic → create visual → publish to social.
graph TD
A["Step 0: Fetch User Accounts<br/>GET /v2/users/me/accounts"] --> B["Step 1: Create Source<br/>POST /v2/source-resolutions-v3"]
B --> C["Step 2: Poll Source<br/>GET /v2/source-resolutions-v3/:id<br/>Until status = completed"]
C --> D["Step 3: Create Visual<br/>POST /v2/videos/from-templates<br/>Use source content in prompt"]
D --> E["Step 4: Poll Visual<br/>GET /v2/videos/creations/:id<br/>Until status = done"]
E --> F["Step 5: Create Post<br/>POST /v2/posts<br/>Use mediaUrl from step 4"]
F --> G["Step 6: Poll Post<br/>GET /v2/posts/:postSubmissionId<br/>Until status = published"]
G --> H["Done! Post is live"]
style A fill:#e1f5ff
style H fill:#c8e6c9
Pseudocode for Agents
1. accountsList = GET /v2/users/me/accounts
2. sourceId = POST /v2/source-resolutions-v3 (specify sourceType: youtube, article, text, etc.)
3. LOOP: source = GET /v2/source-resolutions-v3/:sourceId
- IF status = "completed": BREAK
- IF status = "failed": STOP, report error
- ELSE: WAIT at least 10 seconds, then check again
4. videoId = POST /v2/videos/from-templates (use source.content in prompt)
5. LOOP: video = GET /v2/videos/creations/:videoId
- IF item.status = "done": BREAK
- IF `item.error` is set: STOP, report error
- IF item.status is "creation-from-template-failed" or "insufficient-credits": STOP, report error
- IF item.status = "draft": STOP, report that no rendered result is available
- ELSE: WAIT at least 15 seconds, then check again
6. postSubmissionId = POST /v2/posts (accountId from step 1, mediaUrl/imageUrls from step 5)
- For social platforms, set content.platform and target.targetType to the same value
7. LOOP: post = GET /v2/posts/:postSubmissionId
- IF status = "published": BREAK
- IF status = "failed": STOP, check errorMessage
- IF status = "scheduled": STOP, report scheduledTime
- ELSE: WAIT at least 10 seconds, then check again
8. RETURN: post.publicUrl
4. Managing the Content Calendar
Goal: View, update, reschedule, or delete scheduled posts. Manage the recurring time slots that define your posting cadence.
How Slots and Schedules Work Together:
- Slots define recurring time windows (e.g., "Monday 9 AM for Twitter"). Create them with
POST /v2/schedule/slots. - When you publish with
useNextFreeSlot: true, Blotato finds the next open slot matching the target platform and queues the post at that time. - A slot is "occupied" when a scheduled post is already queued at that time. The next
useNextFreeSlotcall skips occupied slots. - Schedules are the queued posts. Slots are the time windows. Manage them separately.
Endpoints:
- Schedules:
GET /v2/schedules,GET /v2/schedules/:id,PATCH /v2/schedules/:id,DELETE /v2/schedules/:id(docs) - Slots:
GET /v2/schedule/slots,POST /v2/schedule/slots,PATCH /v2/schedule/slots/:id,DELETE /v2/schedules/slots/:id,POST /v2/schedule/slots/next-available(docs)
Schedule Response Shape
The draft field in a schedule is the same shape as the post object in Publish Post:
{
"id": "sch_abc123",
"scheduledAt": "2026-04-01T14:00:00.000Z",
"account": {
"id": "98432",
"name": "Jane Smith",
"username": "janesmith",
"profileImageUrl": "https://...",
"subaccountId": null,
"subId": null,
"subaccountName": null
},
"draft": {
"accountId": "98432",
"content": {
"text": "Scheduled post content",
"mediaUrls": [],
"platform": "twitter"
},
"target": {
"targetType": "twitter"
}
}
}
Note: The response uses
scheduledAtfor the publish time. The update endpoint acceptsscheduledTimeas the input field name.
Rescheduling to the Next Free Slot
The PATCH /v2/schedules/:id endpoint accepts scheduledTime but not useNextFreeSlot. To move a post to the next available slot:
1. POST /v2/schedule/slots/next-available
Body: { "platform": "twitter", "accountId": "98432" }
Response: { "slot": { "slotId": "slot_1", "slotTime": "2026-04-02T09:00:00Z" } }
2. PATCH /v2/schedules/sch_abc123
Body: { "patch": { "scheduledTime": "2026-04-02T09:00:00Z" } }
Pseudocode for Calendar Management
1. schedules = GET /v2/schedules (paginate with cursor if needed)
2. Display scheduled posts to user (scheduledAt, account info, draft content)
3. To reschedule: PATCH /v2/schedules/:id { patch: { scheduledTime: "new ISO 8601" } }
4. To update content: PATCH /v2/schedules/:id { patch: { draft: { full post object } } }
5. To delete: DELETE /v2/schedules/:id
6. To reschedule to next free slot:
a. nextSlot = POST /v2/schedule/slots/next-available { platform, accountId }
b. PATCH /v2/schedules/:id { patch: { scheduledTime: nextSlot.slot.slotTime } }
Error Handling
All asynchronous operations can fail during processing. Handle failures gracefully:
Status Failure
When polling returns status: "failed", check the error message:
Source Failure (Get Source endpoint):
{
"status": "failed",
"message": "Unable to extract content from URL"
}
Video Failure (Get Visual Status endpoint):
{
"item": {
"status": "script-ready",
"error": "2/5 media failed to generate. The video has been saved as a draft."
}
}
Post Failure (Get Post Status endpoint):
{
"postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "failed",
"errorMessage": "Invalid account credentials"
}
Retry Strategy
- Don't retry automatically on failure - most failures are permanent
- Log the error message and report it to the user
- Inform user that the operation failed and provide next steps
- Retry failed reads after a delay. For a create request with an uncertain result, check existing work before resubmitting. For
429, wait and reduce request frequency. See Errors and retries.
Platform-Specific Setup
Different platforms require different fields and have different requirements. See detailed guides:
- Instagram Setup - Reels, Stories, Collaborators, Alt Text
- LinkedIn Setup - Company Pages, Professional Network
- Facebook Setup - Page ID, Media Types
- Platform Requirements - All platforms at a glance
When publishing, always include the required fields for the target platform:
- Facebook:
target.pageId(required),target.mediaType-- required"reel"for videos (regular feed videos no longer supported), optional"story"for Stories, omit for text/image posts - LinkedIn:
target.pageId(optional) - Pinterest:
target.boardId(required) - YouTube:
target.playlistIds(optional - array of playlist IDs from subaccounts) - TikTok:
target.privacyLevel,target.disabledComments, etc. (required) - Instagram:
target.mediaType(optional - default is "reel") - Twitter, Threads, Bluesky: Minimal required fields
Machine-readable sources
Use the connected MCP schemas for tool calls and OpenAPI for REST requests. Individual tutorial pages are not required to follow the workflows in this reference.
Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.
Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.
Perform an HTTP GET request on the following URL with the ask and goal query parameters:
GET https://help.blotato.com/start-with-an-ai-agent/llm.md?ask=<question>&goal=<user_goal>
ask is the immediate question: it should be specific, self-contained, and written in natural language.
goal is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with ask=how do I create an API token, a goal like automate deployments from our CI pipeline lets GitBook tailor the answer to that use case.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.
Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.