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 .md to 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

  1. For MCP, configure Streamable HTTP at https://mcp.blotato.com/mcp with OAuth or the blotato-api-key header supported by your client.
  2. For REST, use https://backend.blotato.com/v2 with the blotato-api-key header. Keep keys out of chat messages, documentation, and shared configuration.
  3. Verify MCP with blotato_list_accounts, or REST with GET /v2/users/me/accounts. An empty account list is a successful authenticated result.
  4. 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

  1. Use only tools exposed by the connected client. REST and MCP do not expose identical operations or argument shapes.
  2. Read the selected tool's schema. Get account, Page, board, playlist, post, schedule, and template IDs from responses rather than inventing them.
  3. 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.
  4. Pass public media URLs directly. For a local file, request upload URLs, PUT the bytes, verify upload success, then use the returned public URL.
  5. Save returned IDs. Follow each operation's completion states below. A submitted or scheduled request is not proof of publication.
  6. After an uncertain write response, check existing work before retrying. A repeated create request risks duplicate content.
  7. 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

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.

  1. Identify the requested outcome and whether you are executing it or explaining it.
  2. Identify the surface: Blotato website, MCP, REST, n8n, or Make.
  3. Identify the client, destination platform, and failing stage when relevant.
  4. Identify the artifact: workflow JSON, local media file, hosted media URL, generated visual, draft, scheduled item, or published post.
  5. 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

  1. Select the exact client in MCP setup, or use the REST quickstart for HTTP, n8n, or Make.
  2. Confirm paid access. Generating an API key during a trial starts billing. Read authentication before generating a key.
  3. Call blotato_list_accounts, or GET /v2/users/me/accounts.
  4. 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

OutcomeExecute through API or MCPExplain website actions
Connect a social destinationIDs and destinationsSocial account settings
Publish or cross-postPublish and verifyCreate posts
Schedule, reschedule, or cancelManage schedulesCalendar
Upload or use existing mediaUpload and prepare mediaAttach media
Generate images, carousels, or videoGenerate and verifyVideo templates
Extract or repurpose source contentExtract a sourceContext
Inspect performanceAnalyticsCheckpoints and pending data
Read or reply to Instagram and Facebook commentsCommentsInbox
Read or reply to Instagram and Facebook direct messagesMessagesInbox
Set up keyword-triggered repliesDM automationsDM automation guide
Check balance or purchase creditsCreditsBilling and credits
Diagnose a failureErrors and retriesSupport diagnosis

Instructions for the agent

  1. Use only available tools and the selected operation's schema. REST and MCP differ in fields and operation coverage.
  2. Retrieve current IDs. After reconnection, re-list accounts. Never substitute a social-platform post ID, submission ID, or schedule ID for another ID type.
  3. Check platform requirements and media requirements before a write.
  4. Confirm the requested destination and authorization. Connection tests must not publish, send messages, purchase credits, or activate automations.
  5. Record returned IDs. Use operation-specific completion rules, including error fields inside successful HTTP or MCP responses.
  6. Inspect existing work after an uncertain write. Do not blindly repeat a create request.
  7. 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.

ResourceUse
Search and read helpOptional public documentation MCP lookup, separate from account access
MCP toolsAvailable tools and behavior
MCP input indexRequired and optional tool arguments
API reference for agentsGenerated setup, contracts, examples, and completion rules in 1 document
Documentation indexFind a page outside this task index
Full documentation textWhole-corpus retrieval when required
OpenAPI JSONPublished 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

PurposeServerAccess
Look up published helpDocumentation MCP endpointPublic documentation. No Blotato API key or account authorization required.
Work with connected social accountshttps://mcp.blotato.com/mcpFollow 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

  1. Add the documentation endpoint to an HTTP MCP client under a distinct name such as blotato-docs, if a docs connection is needed.
  2. Discover its tools with tools/list.
  3. Call searchDocumentation with a query string.
  4. Select a result for the customer's surface: API/MCP execution or Blotato website instructions.
  5. Call getPage with the result's page URL in url.
  6. Read the page before answering or constructing a request.
ToolInputUse
searchDocumentationqueryRetrieve matching help-page excerpts and URLs.
getPageurlRetrieve 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

  1. Read the task index or documentation index.
  2. Fetch the selected page as Markdown by appending .md to 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

  1. Confirm your paid Blotato subscription. API and MCP access is not included in the free trial.
  2. Connect social accounts in Accounts.
  3. 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

  1. Open Claude connectors.
  2. Add a custom connector named Blotato.
  3. Enter https://mcp.blotato.com/mcp as the URL.
  4. Connect and approve access in the browser.
  5. 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

  1. Open Customize, then Connectors.
  2. Add a custom connector named Blotato.
  3. Enter https://mcp.blotato.com/mcp as the URL.
  4. Connect and approve access in your browser.
  5. 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

  1. Run this command in your terminal:
claude mcp add --transport http blotato https://mcp.blotato.com/mcp
  1. Open Claude Code.
  2. Run /mcp.
  3. Select Blotato and authenticate through the browser.
  4. 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)

  1. In the ChatGPT desktop app, open Plugins, then MCPs.
  2. Click Add, then Add MCP server.
  3. Name it blotato.
  4. Select Streamable HTTP. The form opens on STDIO.
  5. Enter https://mcp.blotato.com/mcp as the URL.
  6. Under Headers, set blotato-api-key to your full API key.
  7. Leave Bearer token env var blank when using the header above.
  8. Save and restart the MCP connection or client.
  9. 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:

  1. Open ChatGPT Plugins.
  2. Click Add in the top right corner, then Add custom MCP server.
  3. Enter the name Blotato, a description, and server URL https://mcp.blotato.com/mcp.
  4. Choose OAuth authentication.
  5. Select I understand and want to continue.
  6. Click Create as a plugin.
  7. Click Connect Blotato.
  8. On the Blotato page, sign in if asked, review the access request, and click Approve access.
  9. Start a new chat with Blotato selected in the tools menu.
  10. 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

  1. Open your personal ~/.cursor/mcp.json configuration.
  2. Add the Blotato entry below, preserving any existing servers.
  3. Replace YOUR_API_KEY with your full key.
  4. Save and restart Cursor.
  5. 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:

  1. Open .vscode/mcp.json in your workspace, preserving any existing servers.
  2. Add the configuration below.
  3. Start the Blotato server from the editor's MCP controls.
  4. Enter your full Blotato API key when prompted.
  5. 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

  1. Run hermes config edit to open your Hermes configuration, or open ~/.hermes/config.yaml.
  2. Add the Blotato entry below under mcp_servers.
  3. Replace YOUR_API_KEY with your full key.
  4. Save and restart Hermes.
  5. 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

  1. Replace YOUR_API_KEY in the command below with your full key.
  2. Run the command in your terminal.
  3. 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:

  1. Open the client's MCP configuration.
  2. Select Streamable HTTP.
  3. Set the URL to https://mcp.blotato.com/mcp.
  4. Complete OAuth if supported, or set a blotato-api-key header to your full API key.
  5. Reload the connection.
  6. 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:

  1. Call blotato_create_presigned_upload_url with your filename (include the extension). It returns a presignedUrl and a publicUrl.
  2. Upload the raw file bytes to presignedUrl with an HTTP PUT (for example curl -X PUT "<presignedUrl>" --data-binary "@<local_file>"). Send raw bytes, not JSON and not multipart form data.
  3. Pass the returned publicUrl in the mediaUrls field of blotato_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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. If the connector shows "Connected" but a tool fails, inspect the returned error. A subscription-related 403 requires an active paid plan. A 401 points to credentials or session authentication. Follow authentication checks. Generating an API key during a trial starts the paid subscription.
  6. An empty account list is a successful call. Connect a social account in Accounts before publishing.
  7. 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.
  8. 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:
    1. Go to Customize > Connectors and fully remove the Blotato connector
    2. Click the + button, choose Add custom connector, and approve access again
    3. To double-check the key itself, see Settings > API
  9. "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 PUT to the presigned upload URL cannot reach database.blotato.io. To allow it:
    1. Go to Claude Cowork/Desktop > Settings > Capabilities > Allow network egress
    2. Set "Package managers only"
    3. Under Additional allowed domains, add database.blotato.io and click Add
    4. Fully quit and restart Claude Cowork/Desktop
    5. 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

  1. Open Settings > API.
  2. Generate or copy your API key.
  3. Include the key in the blotato-api-key header of each request.
  4. Call GET https://backend.blotato.com/v2/users/me/accounts to 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:

MethodConfiguration
OAuthAdd the server URL and complete the browser authorization flow
API key headerSet blotato-api-key to your API key
Bearer headerSet 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

ResultNext action
401 or invalid credentialsRecopy the full API key, or repeat OAuth authorization in the client
403 with a subscription messageCheck the subscription in Billing
OAuth fails but an API-key request succeedsFollow the OAuth session troubleshooting steps for the client
Accounts are missingConfirm 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.

MCPREST API
Use fromAn assistant with MCP toolsHTTP code, n8n, Make, or other workflow tools
Connect tohttps://mcp.blotato.com/mcphttps://backend.blotato.com/v2
AuthenticateOAuth or an API key, depending on the clientblotato-api-key header
Publish inputTool arguments such as accountId, platform, text, and mediaUrlsA JSON body containing post.accountId, post.content, and post.target
Account lookupblotato_list_accounts includes subaccountsFetch accounts, then fetch subaccounts when needed
Immediate post and source completionTools wait internally for up to 20 seconds, then return the available resultSubmit, save the returned ID, and poll the status endpoint
Visual completionCall blotato_get_design_statusPoll the visual status endpoint
ReferenceMCP toolsOpenAPI

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

  1. If your assistant already has blotato_ tools, call those tools directly using their schemas.
  2. If you are adding Blotato to an assistant, follow MCP setup.
  3. If you are building HTTP requests, follow the REST quickstart.
  4. 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.

ToolRequired argumentsOptional arguments
blotato_get_user——
blotato_list_accounts—platform
blotato_list_pinterest_boardsaccountId—
blotato_create_automationaccountId, platform, name, dmMessagepageId, triggers, buttons, followGate, emailGate, webhook, commentReply, isActive
blotato_list_automations—limit, cursor
blotato_list_automation_runsautomationIdlimit, cursor, status, since
blotato_list_automation_logsautomationIdflowRunId, limit, cursor
blotato_get_automation_analyticsautomationId—
blotato_update_automationautomationIdname, triggers, dmMessage, buttons, followGate, emailGate, webhook, commentReply, isActive
blotato_update_automation_triggerautomationId, triggerId, isActive—
blotato_delete_automationautomationId—
blotato_list_comments—limit, cursor, platform, accountId, postId, parentCommentId, since, until
blotato_get_commentcommentId—
blotato_post_commentpostId, textparentCommentId
blotato_get_credits——
blotato_create_presigned_upload_urlfilename—
blotato_list_conversations—limit, cursor, platform, accountId
blotato_get_conversationconversationId—
blotato_list_messages—conversationId, limit, cursor, platform, accountId
blotato_get_messagemessageId—
blotato_send_messageaccountId, platform, recipientId, textpageId, commentId, buttons, quickReplies
blotato_create_postaccountId, platform, textmediaUrls, 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_statuspostSubmissionId—
blotato_list_posts—since, until, limit, cursor, status, platform
blotato_list_schedules—limit, cursor
blotato_get_scheduleid—
blotato_update_scheduleidscheduledTime, post
blotato_delete_scheduleid—
blotato_create_sourcesourceTypeurl, text, customInstructions
blotato_get_source_statusid—
blotato_list_design_templates—search, id
blotato_create_designtemplateIdinputs, prompt, render, title
blotato_get_design_statusid—
blotato_list_top_posts—since, until, platform, sortBy, limit
blotato_get_post_analyticsid—

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 id and name. Use id as boardId in 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 (min and max), and pricePer1000CreditsUsd.

Publishing

blotato_create_post

Create and publish (or schedule) a post to a social media platform.

  • Input:
    • accountId (required) - from blotato_list_accounts
    • platform (required) - twitter, instagram, facebook, tiktok, linkedin, pinterest, bluesky, threads, or youtube
    • text (required) - post content
    • mediaUrls (optional) - array of public media URLs
    • scheduledTime (optional) - ISO 8601 datetime
    • useNextFreeSlot (optional) - use next available schedule slot
    • pageId (optional) - for Facebook/LinkedIn pages
    • mediaType (optional) - for Instagram/Facebook: reel or story. Facebook videos must be "reel" (regular feed videos no longer supported).
    • trial (optional) - for Instagram reels: object with graduationStrategy ("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 TikTok
    • additionalPosts (optional) - array of additional posts for threads (Twitter, Bluesky, Threads). Each entry has text and mediaUrls. The first post uses the top-level text and mediaUrls fields. Blotato handles reply chaining.
    • boardId (optional) - for Pinterest (get from blotato_list_pinterest_boards)
    • title (optional) - for Pinterest or YouTube
    • privacyStatus (optional) - for YouTube: public, private, or unlisted
    • playlistIds (optional) - for YouTube: array of playlist IDs from blotato_list_accounts to add the video to playlists
    • thumbnailUrl (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: 50
    • cursor (optional) - pagination cursor from a previous response
    • status (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 a state object. A published state includes analytics.latest and analytics.history, or analytics: null. Includes cursor for 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 accepts twitter, instagram, facebook, threads, or bluesky as 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, or reach_count. Defaults to views_count. For Twitter/X, comments ranking uses replies_count when comments are not reported, and views ranking uses impressions_count when views are not reported.
    • limit (optional) - number of posts to return. Min: 1, Max: 100. Default: 20
  • Output: array of items, each with id, content, postUrl, platform, createdAt, mediaUrls, latestMetrics, and metricsHistory.

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), and history (array of snapshots, each with fetchedAt and metrics).

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: 50
    • cursor (optional) - pagination cursor from a previous response
    • platform (optional) - filter by platform: instagram or facebook
    • accountId (optional) - filter to a single connected account
    • parentCommentId (optional) - filter to direct replies to a single comment
    • postId (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 timestamp
    • until (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, and errorMessage (when failed). Includes cursor for 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, and errorMessage (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 8000
    • parentCommentId (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: 50
    • cursor (optional) - pagination cursor from a previous response
    • platform (optional) - filter by platform: instagram or facebook
    • accountId (optional) - filter to a single connected account
  • Output: array of conversations with id, platform, participants, updatedAt, and createdAt. Includes cursor for 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, and updatedAt

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: 50
    • cursor (optional) - pagination cursor from a previous response
    • conversationId (optional) - filter to a single conversation
    • platform (optional) - filter by platform: instagram or facebook
    • accountId (optional) - filter to a single connected account
  • Output: array of messages with id, conversationId, direction, text, payload, status, senderId, recipientId, and createdAt. direction is incoming for messages you receive and outgoing for messages you send. Includes cursor for 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, and createdAt

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) - instagram or facebook
    • pageId (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's senderId (from blotato_list_messages)
    • text (required) - message body. Instagram messages are limited to 1000 bytes, Facebook to 2000 characters. With buttons set, the limit drops to 640 characters
    • commentId (optional) - to send a private reply to a comment instead of a direct message, pass the comment's Blotato ID
    • buttons (optional) - Facebook and Instagram only. 1 to 3 call-to-action buttons pinned under the message. See Buttons and Quick Replies
    • quickReplies (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_url opens a link, postback reports the tap back to you
  • title - button label, 1 to 20 characters
  • url - required for web_url, starts with https://
  • payload - required for postback, 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_accounts
    • platform (required) - instagram or facebook
    • pageId (required for Facebook) - the Facebook Page from the account's subaccounts
    • name (required) - automation label, 1 to 60 characters
    • triggers (optional) - up to 2 triggers, at most one comment-received and one message-received. Each has type, 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), and isActive (default true). For an externally published Instagram post already tracked through an incoming comment, use the comment's non-null postId after verifying the account and platformPostId. Omitting postId matches any post and requires approval for this scope. See post targeting. A comment-received trigger fires on top-level comments only, not on replies to comments. Any one trigger firing starts a single run. Omit triggers for a draft with no triggers
    • dmMessage (required) - the message sent when a trigger fires, 1 to 640 characters
    • buttons (optional) - up to 3 link buttons, each with type: "url", a title of 20 characters or fewer, and a url
    • followGate (optional, Instagram only) - message (1 to 640 characters) and buttonTitle (20 characters or fewer, default I'm following). Holds the DM back until the contact follows the account. Rejected on a Facebook automation
    • emailGate (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 it
    • webhook (optional) - method (GET, POST, PUT, PATCH, or DELETE), url (public http(s), 2048 characters or fewer), and headers (optional). Called once the DM sends
    • commentReply (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 off
    • isActive (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: 50
    • cursor (optional) - pagination cursor from a previous response
  • Output: array of automations with id, accountId, name, platform, target, triggers (each with id, type, keywords, postId, and isActive), dmMessage, buttons, emailGate, followGate, webhook, commentReply, isActive, publishedVersionId, createdAt, updatedAt, and stats. stats contains triggered, completed, and failed counts from the last 24 hours plus lastRunAt, which is null when the automation has never run. Archived automations do not appear. Includes cursor for 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_automations
    • name (optional) - new automation label, 1 to 60 characters
    • triggers (optional) - replaces every trigger. Up to 2, at most one per type. [] removes all
    • dmMessage (optional) - replaces the message text
    • buttons (optional) - replaces the link buttons. [] removes all
    • followGate (optional, Instagram only) - replaces the follow gate. Pass null to remove it
    • emailGate (optional) - replaces the email gate. Pass null to remove it
    • webhook (optional) - replaces the webhook. Pass null to remove it
    • commentReply (optional) - replaces the public reply to the comment. Pass null to turn it off
    • isActive (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_automations
    • triggerId (required) - trigger ID from the automation's triggers
    • isActive (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_automations
    • limit (optional) - number of runs per page. Min: 1, Max: 250. Default: 50
    • cursor (optional) - pagination cursor from a previous response
    • status (optional) - array of statuses to include: running, waiting, completed, expired, superseded, failed. Omit to include all
    • since (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, and updatedAt. A failed run's error includes code, message, and, when available, action and details with 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_automations
    • flowRunId (optional) - filter to a single run, from blotato_list_automation_runs
    • limit (optional) - number of logs per page. Min: 1, Max: 250. Default: 50
    • cursor (optional) - pagination cursor from a previous response
  • Output: array of logs with id, flowRunId, nodeId, level (info, warning, error), message, context, and createdAt

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-query
    • url (optional) - required for URL-based source types
    • text (optional) - required for text and perplexity-query source types
    • customInstructions (optional) - guide extraction (e.g., "focus on key takeaways", "summarize in 5 bullet points")
  • Output: id and status. A completed result includes title, content, and referenceUrl when 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, title and content when completed, message when 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: items containing id, description, and available inputs. Do not depend on a title or name field in the MCP result. For names through REST, request fields=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_templates
    • inputs (optional) - template-specific values. Use {} with a prompt for a first request.
    • prompt (optional) - describe what you want in natural language
    • render (optional, default: true)
    • title (optional) - title for the design
  • Output: item.id (the design ID) and item.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), and item.error when the design fails
  • Status values: queueing, generating-script, script-ready, generating-media, media-ready, exporting, done, creation-from-template-failed, insufficient-credits, or draft
  • Stop polling when item.error is set, including on an intermediate status. Use media URLs after item.status reaches done. 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: 20
    • cursor (optional) - pagination cursor from a previous response
  • Output: array of schedules with ID, scheduledAt, account info, and draft content. Includes count (total) and cursor (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_schedules
    • scheduledTime (optional) - new ISO 8601 timestamp, must be in the future
    • post (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) and publicUrl (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:

  1. Call blotato_create_presigned_upload_url with your filename
  2. PUT the file contents to the returned presignedUrl with the correct Content-Type header
  3. Use the returned publicUrl in blotato_create_post's mediaUrls field

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

  1. Call blotato_list_accounts through MCP, or GET /v2/users/me/accounts through REST.
  2. Match the returned platform and account name to the user's intended destination.
  3. Use the returned account id as accountId.
  4. 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.

DestinationIdentifierWhere to get it
Facebook PagepageId, requiredMCP account subaccounts, or REST GET /v2/users/me/accounts/:accountId/subaccounts
LinkedIn company PagepageId, required for this destinationMCP account subaccounts, or the REST subaccounts endpoint
LinkedIn personal profileOmit pageIdUse the LinkedIn accountId
Pinterest boardboardId, requiredblotato_list_pinterest_boards, or GET /v2/social/pinterest/boards?accountId=...
YouTube playlistplaylistIds, optionalMCP 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.

  1. Read the failed request's accountId, content.platform, and target.targetType.
  2. Retrieve accounts using the same credential or MCP connection used for publishing.
  3. Select the returned account for the user's intended platform and destination.
  4. Retrieve a separate Page ID when required. Do not put a Page ID in accountId.
  5. 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

IDUse
postSubmissionId from create-postPoll publishing status with blotato_get_post_status or GET /v2/posts/:postSubmissionId
Published post ID from post listingsFetch analytics or comments for the published post
Scheduled post id from schedule listingsGet, update, or cancel the scheduled post
Source idCheck source extraction
Visual item.idCheck visual generation
Comment idFetch the comment or check reply completion
Conversation or message idFetch the corresponding conversation or message
Automation flow and trigger IDsManage 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

OperationStatus lookupCompletion
Immediate postblotato_get_post_status or GET /v2/posts/:postSubmissionIdpublished succeeds. failed stops the workflow. in-progress needs another check.
Scheduled postCreate response, then schedule lookup when neededReport the returned scheduledTime. scheduled means scheduled, rather than published.
Sourceblotato_get_source_status or GET /v2/source-resolutions-v3/:idcompleted succeeds. failed stops the workflow. queued and processing need another check.
Visualblotato_get_design_status or GET /v2/videos/creations/:iditem.status: done supplies finished media. Stop on item.error, creation-from-template-failed, or insufficient-credits.
Commentblotato_get_comment or GET /v2/comments/:commentIdposted succeeds. failed stops the workflow.
Messageblotato_get_message or GET /v2/messages/:messageIdsent 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.

  1. Wait at least 10 seconds between post or source status calls.
  2. Wait at least 15 seconds between visual status calls.
  3. For queued comments and messages, space status checks to stay within the endpoint rate limits.
  4. 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 inputNext action
Public image or video URLPass it directly in mediaUrls. No upload step required.
Finished Blotato visualPass the returned mediaUrl or imageUrls. No upload step required.
File on the user's computer or in the agent's workspaceComplete a presigned upload, then pass publicUrl.
Private download link or editor/share pageObtain a public downloadable media URL, or upload the file bytes.

Upload a local file

  1. Call blotato_create_presigned_upload_url with filename, including its extension. For REST, call POST /v2/media/uploads with the same field.
  2. Send an HTTP PUT to the returned presignedUrl, with the raw file bytes as the request body.
  3. After the upload succeeds, pass the returned publicUrl in the publish request's mediaUrls array.

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.

  1. Check the platform media requirements.
  2. Check the file's container, codecs, dimensions, aspect ratio, duration, bitrate, and size.
  3. If a video longer than 120 seconds needs cropping, resizing, or re-encoding, edit and export it before publishing.
  4. Use a URL which serves the media without a login.
  5. 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.

  1. Inspect the file's container metadata, including major_brand. Do not identify the format from its filename alone.
  2. Export the source as MP4 with H.264 video and AAC audio. Renaming the extension does not change the container.
  3. Inspect the exported file and check its dimensions, bitrate, size, and duration against the destination's requirements.
  4. 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.

ResultMeaningAgent response
Create response with postSubmissionIdBlotato accepted the requestSave the ID
in-progressNo failed, published, or scheduled result was foundVerify the saved submission ID and poll within a waiting limit
scheduledThe post is scheduledReport scheduledTime and stop immediate polling
publishedPublishing completedReturn publicUrl when supplied
failedPublishing stoppedExplain errorMessage and resolve the cause

Publish now

  1. Fetch the destination account and required IDs.
  2. Submit the post once.
  3. Follow status polling.
  4. Report the returned outcome.

Publish later

  1. Resolve the user's requested date, time, and timezone.
  2. Submit with a future scheduledTime or useNextFreeSlot: true.
  3. Report the resolved UTC time in the user's timezone.
  4. 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

  1. Resolve the user's date, time, and timezone. Ask for the timezone when it is unknown.
  2. 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.
  3. Set scheduledTime in the create-post request.
  4. Read the returned scheduledTime and 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

  1. Set up the calendar's schedule slots.
  2. Set useNextFreeSlot: true in place of a specific scheduledTime.
  3. 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

  1. List schedules with blotato_list_schedules or GET /v2/schedules.
  2. Read the selected scheduled post with blotato_get_schedule or GET /v2/schedules/:id.
  3. Update it with blotato_update_schedule or PATCH /v2/schedules/:id, or cancel it with blotato_delete_schedule or DELETE /v2/schedules/:id.
  4. 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.

OperationRequests per minute
Create post30
List posts or get post submission status60 for each route
Get post analytics60
Upload media from a URL with POST /v2/media30
Create a presigned upload URL120
List Pinterest boards45
List comments or get a comment60 for each route
Post a comment30
List conversations, get a conversation, list messages, or get a message60 for each route
Send a message30
List or get DM automations, runs, logs, or analytics60 for each route
Create, update, delete an automation, or update a trigger30 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

  1. Stop requests to the limited route after 429.
  2. Wait for the retry interval when the response supplies one.
  3. Reduce concurrency and request frequency before resuming.
  4. 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 symptomNext step
401, invalid API key, or invalid sessionFollow authentication checks
Subscription-related 403Check Billing
404Re-fetch the record and verify the ID type and account
Validation error, often 422Correct the named field using the endpoint schema
429Wait for the retry interval if provided, then reduce request frequency
Network error or 5xx on a readRetry with a delay and a bounded attempt count
Network error after a create requestCheck existing work before submitting again
Post status failedRead errorMessage and the platform requirements
Visual response contains item.errorStop polling and explain the generation error
Empty analytics or inbox resultCheck the feature's sync timing and supported platforms or inbox setup
Media fetch or conversion failureFollow the media checklist

Inspect a failed request

  1. Open the Logs.
  2. Select the request.
  3. Read its payload, response, and error message.
  4. 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

  1. Save every submission or creation ID returned by a successful create request.
  2. If a status call fails, retry the status call with the saved ID.
  3. If creation timed out without an ID, inspect the dashboard and existing posts or schedules before creating another item.
  4. For a failed post, correct the error before a new submission. An unchanged retry often fails for the same reason.
  5. 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

  1. Answer the question using the context already supplied.
  2. Give the next supported action for the customer's surface.
  3. State what proves success or what remains unresolved.
  4. 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 symptomChecks before the next actionEvidence or stop condition
“Connected”, but no toolsIdentify 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 rejectedCheck 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 accountRe-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 publishedRetrieve 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 creditsInspect 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 draftsCheck 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 videoOpen 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 inboxCheck 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-inactiveSeparate 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.

  1. Identify where the file exists: the customer's device, the assistant's workspace, or a remote URL.
  2. For local media, verify the assistant has file access and an HTTP upload tool. A presigned URL alone does not upload bytes.
  3. 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.
  4. For remote media, verify a direct file response without interactive login. Browser access alone does not prove server-to-server access.
  5. Inspect the actual container, codecs, file size, duration, and dimensions. An .mp4 extension is not a metadata probe.
  6. Apply conversion and platform requirements. A video longer than 120 seconds is not automatically prohibited, but must already satisfy the destination's requirements.
  7. After correction, verify the publishing result. Upload success does not prove publication.

Repeated failure or unclear cause

  1. Carry forward completed checks and their results. Do not resend the same checklist without new evidence.
  2. Record the client or integration, operation, destination platform, timestamp and timezone, request/submission/visual ID, exact error, and sanitized request shape.
  3. Record expected versus observed behavior and attempted fixes.
  4. Stop if the next action risks another charge, duplicate post, wrong destination, or unauthorized account change.
  5. 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

  1. Record the intended social account or Page, content, and submission or scheduled time with timezone.
  2. 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.
  3. Open any returned platform URL and check the intended account on the platform.
  4. Read the exact error before changing media, reconnecting an account, or retrying.
  5. 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

  1. Retrieve the postSubmissionId from the original create response. Do not substitute a schedule ID, published-post ID, or guessed UUID.
  2. Call blotato_get_post_status or Get Post Status with that ID and the original Blotato account credentials.
  3. Follow the status-specific completion rules.
  4. Inspect existing posts and schedules when the submission result is missing or inconsistent.
  5. 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

ObservationSupported conclusion and next step
Schedule disappeared at its due timeThe schedule is no longer in that list. Check publishing results before assuming failure or success.
Published record, but platform URL is absent or inaccessibleBlotato recorded publication. Check the destination and platform account. An inaccessible URL alone does not prove moderation, deletion, or suppression.
Failed resultRead 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 platformRecord 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 onceInvestigate 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.

  1. Call blotato_list_accounts with {"platform":"twitter"}. The result is an account array, not REST's items wrapper:
[
  {
    "id": "98432",
    "platform": "twitter",
    "fullname": "Example account",
    "username": "example",
    "subaccounts": [],
    "requiredFields": {}
  }
]
  1. Match the requested account. An empty list confirms authentication but requires connecting an account in Accounts. Multiple matching destinations require clarification before a write.
  2. Call blotato_create_post:
{
  "accountId": "98432",
  "platform": "twitter",
  "text": "Approved post text.",
  "mediaUrls": []
}
  1. Read the tool result, including isError, status, and any error text. If processing continues, retain postSubmissionId and call blotato_get_post_status at least 10 seconds later:
{
  "postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
  1. 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

  1. Call blotato_list_accounts to find accountId and any Page IDs.
  2. Read the destination's platform guide. For Pinterest, call blotato_list_pinterest_boards to get boardId.
  3. Supply public media URLs, or complete the local upload.
  4. Call blotato_create_post with the account, platform, content, and required platform fields.
  5. If the returned status is in-progress, call blotato_get_post_status with the returned postSubmissionId, waiting at least 10 seconds between checks.
  6. Return published and the supplied publicUrl, or explain failed and its errorMessage.

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

  1. Fetch GET /v2/users/me/accounts and any required subaccounts or Pinterest boards.
  2. Send POST /v2/posts using the Publish Post schema.
  3. Save postSubmissionId from the response.
  4. Poll GET /v2/posts/:postSubmissionId according 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

  1. Send GET https://backend.blotato.com/v2/users/me/accounts?platform=twitter with the blotato-api-key header. Select the matching items[].id as accountId.
  2. Send this body to POST https://backend.blotato.com/v2/posts with the same auth header and Content-Type: application/json:
{
  "post": {
    "accountId": "98432",
    "content": {
      "platform": "twitter",
      "text": "Approved post text.",
      "mediaUrls": []
    },
    "target": { "targetType": "twitter" }
  }
}
  1. Save the accepted response's postSubmissionId:
{
  "postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
  1. Send GET https://backend.blotato.com/v2/posts/a1b2c3d4-e5f6-7890-abcd-ef1234567890 with 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"
}
ResultAgent action
publishedReport success and the returned publicUrl when supplied. Do not construct a guessed URL.
failedStop. Read errorMessage, correct the cause, and obtain authorization for any new submission outside the original request.
in-progressPoll the saved ID with a waiting limit. Report the ID and unresolved state if the limit is reached.
scheduledReport the returned scheduledTime. Do not describe it as published.
No response or an uncertain writeInspect 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

  1. Select the accounts requested by the user.
  2. Adapt the media and target fields for each platform.
  3. Create a separate submission for each destination.
  4. 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

  1. Call blotato_list_accounts and select the destination.
  2. Resolve the requested date and timezone, or choose the next free slot.
  3. Call blotato_create_post with scheduledTime or useNextFreeSlot: true.
  4. Verify the resolved scheduledTime and report it in the user's timezone. If no time is returned, retrieve status using the saved postSubmissionId before 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

  1. Call blotato_list_schedules to locate the scheduled item.
  2. Call blotato_get_schedule to read its content and time.
  3. Call blotato_update_schedule with the intended change, or blotato_delete_schedule to cancel.
  4. 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.

  1. Ensure the assistant has access to the file in its workspace.
  2. Call blotato_create_presigned_upload_url with the filename and extension.
  3. Upload the bytes to presignedUrl with an HTTP PUT.
  4. Use publicUrl in blotato_create_post after the upload succeeds.
  5. 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.

  1. Send PUT to presignedUrl with the raw file bytes. Do not use JSON or multipart form data.
  2. Check the upload response for success before using publicUrl.
  3. Confirm the file meets the plan and platform limits.
  4. Pass publicUrl in the publish request's mediaUrls array.
  5. 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

  1. Call blotato_list_design_templates, or GET /v2/videos/templates, to select a template and inspect its inputs.
  2. Call blotato_create_design, or POST /v2/videos/from-templates, with templateId, template-specific inputs, a prompt when needed, and render: true for 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.

  1. Save the returned item.id.
  2. Call blotato_get_design_status, or GET /v2/videos/creations/:id, at least 15 seconds apart.
  3. Stop when item.status is done, or when item.error or a failure state appears.
  4. Use the returned item.mediaUrl or item.imageUrls for 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

  1. 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.
  2. Call blotato_create_design with this shape. For REST, send the same body to POST https://backend.blotato.com/v2/videos/from-templates with Content-Type: application/json and the blotato-api-key header:
{
  "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
}
  1. Save item.id from the response. A queueing status means accepted, not finished:
{
  "item": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "queueing"
  }
}
  1. Call blotato_get_design_status with {"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"}, or GET /v2/videos/creations/a1b2c3d4-e5f6-7890-abcd-ef1234567890. Substitute the saved ID and wait at least 15 seconds between checks.
  2. On done, read the returned item.imageUrls for image outputs or item.mediaUrl for video. Do not guess the URL or reuse the source input as the generated result.
  3. Stop on item.error, creation-from-template-failed, or insufficient-credits. A draft or script-ready record without completed media is not ready to publish. Inspect visual status for next steps.
  4. 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

  1. Follow Make your first AI video to choose a template and generate a visual.
  2. Review the finished output.
  3. 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

  1. Call blotato_create_source with 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."
}
  1. Save the returned id. The tool waits internally for up to 20 seconds. If the result is still queued or processing, call blotato_get_source_status with 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

  1. 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.
  2. On completed, use the returned content and title. 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.
  3. On REST or MCP status lookup failed, inspect message. The MCP create tool reports extraction failure through isError with the source ID, while the status tool returns a failed status in its JSON result. Check both the tool error flag and the operation status. Correct the source or access problem before another extraction attempt.
  4. After a timeout, look up the saved ID instead of submitting another extraction. If no ID was received, report the uncertain outcome before retrying.
  5. 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

  1. Report the returned metric values and snapshot times. Different collection times affect comparisons.
  2. Treat missing or null metrics as unavailable, not 0. If the response is an error, preserve its message instead of manufacturing an empty result.
  3. 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.
  4. Check the post's platform, eligibility, and publication time against refresh checkpoints. Reading analytics returns stored snapshots. It does not trigger collection.
  5. 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

  1. Use an authenticated connection and an Instagram or Facebook account with comments enabled and the required permissions.
  2. Call blotato_list_posts to find the selected published post's Blotato ID.
  3. Call blotato_list_comments with the following shape. Replace the example postId with the returned ID.
{"postId": "123e4567-e89b-12d3-a456-426614174000", "limit": 50}
  1. Read items. If a cursor is returned and more results are needed, pass it with the same filters in the next call. A missing cursor marks the end.
  2. 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 statusNext action
postedReport the reply as posted.
queued or processingRead the same comment again. Do not send another reply.
failedStop and inspect errorCode and errorMessage.
deletedReport 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

  1. Use an authenticated connection and confirm messaging permissions and the platform messaging window.
  2. Call blotato_list_conversations, filtering by the intended account and platform. Select the conversation from items. Follow returned cursors until the requested conversation is found or the results end.
{"accountId": "98434", "platform": "instagram", "limit": 50}
  1. Call blotato_list_messages with the selected conversation's id. Replace all example IDs with returned values.
{"conversationId": "cnv_abc123", "limit": 50}
  1. Read direction before selecting the reply recipient. For an incoming message, the other participant is senderId. For an outgoing message, the other participant is recipientId. Use the conversation's accountId as 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.

  1. On outgoing sent, report the message as sent. This does not establish the recipient read it.
  2. On failed, stop and preserve errorCode and errorMessage. Resolve permissions, messaging-window, recipient, or account errors before another attempt.
  3. For queued or processing, 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.
  4. 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.

  1. Call blotato_list_accounts to identify the account.
  2. Call blotato_list_automations to inspect existing flows before creating a duplicate.
  3. Read the automation schema and match the trigger and message to the user's request.
  4. Call blotato_create_automation or blotato_update_automation for the requested flow.
  5. Inspect the returned flow and activation state.
  6. Use blotato_list_automation_runs, blotato_list_automation_logs, and blotato_get_automation_analytics to 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.

  1. Call blotato_get_credits to read the balance, account email, pricing, and purchase limits.
  2. State the returned account email before directing the user to purchase credits. Credits belong to the account and are non-transferable.
  3. Direct the user to Settings > Billing.
  4. 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

PlanAPI Access
Free TrialNo
StarterYes
CreatorYes
AgencyYes

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:

IntegrationBase 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:

Related guide


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

  1. Follow the Blotato node installation guide for n8n Cloud or self-hosted n8n.
  2. Configure and verify the credential.
  3. Use the first-post workflow after selecting the intended account.

Make

  1. Open any scenario in Make
  2. Click the "+" icon to add a module
  3. Search for "Blotato"
  4. Select the Blotato module

Choose an automation tutorial

New to building automations? Start here:

Choose your preferred integration path:

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:

Related guide


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:

API Reference for LLMs

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.

MethodPathReference
GET/v2/dm-automationsList automations
POST/v2/dm-automationsCreate 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}/runsList automation runs
GET/v2/dm-automations/{id}/logsList automation logs
GET/v2/dm-automations/{id}/analyticsGet automation analytics
PATCH/v2/dm-automations/{flowId}/triggers/{triggerId}Update trigger
GET/v2/commentsList comments
POST/v2/commentsPost comment
GET/v2/comments/{commentId}Get comment
GET/v2/creditsGet credits
POST/v2/creditsBuy credits
POST/v2/mediaUpload URL
POST/v2/media/uploadsUpload local file
GET/v2/conversationsList conversations
GET/v2/conversations/{conversationId}Get conversation
GET/v2/messagesList messages
POST/v2/messagesSend message
GET/v2/messages/{messageId}Get message
GET/v2/integrations/oauth2/linkedin/pagesFind LinkedIn pages
GET/v2/social/pinterest/boardsList Pinterest boards
GET/v2/postsList posts
POST/v2/postsCreate post
GET/v2/posts/{postSubmissionId}Get submission status
GET/v2/posts/{id}/analyticsGet post analytics
GET/v2/analyticsRank posts
GET/v2/analytics/platformsCompare platforms
GET/v2/analytics/summaryGet analytics summary
GET/v2/published-postsSearch published posts
GET/v2/published-posts/{id}Get a published post
GET/v2/schedulesList 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-v3Extract source
GET/v2/source-resolutions-v3/{id}Get source status
GET/v2/users/meGet user
GET/v2/users/me/usageGet usage
GET/v2/users/me/accountsList accounts
GET/v2/users/me/accounts/{accountId}/subaccountsList subaccounts
DELETE/v2/videos/{id}Delete visual
GET/v2/videos/creations/{id}Get visual status
POST/v2/videos/from-templatesCreate visual
GET/v2/videos/templatesList 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

NameTypeDescription
idstringThe unique ID of the user.
subscriptionStatusstringThe user's subscription status (e.g., active, generic_pro).
subscriptionPlanstringThe user's plan tier: starter, creator, or agency.
apiKeystring[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

NameTypeDescription
accountsintegerNumber 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.
contactsintegerNumber of contacts messaged this month, counting toward the active-contacts limit.
contactsLimitinteger 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

FieldTypeRequiredDescription
platformstringNoFilter 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"
    }
  ]
}
FieldTypeDescription
itemsarrayList of connected accounts
items[].idstringAccount ID. Use this as accountId when publishing.
items[].platformstringPlatform type (e.g., twitter, facebook, instagram)
items[].fullnamestringDisplay name of the account
items[].usernamestringUsername 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

FieldTypeRequiredDescription
accountIdstringYesThe account ID from the List Accounts endpoint

Response

Status Code: 200 OK

{
  "items": [
    {
      "id": "123456789",
      "accountId": "98433",
      "name": "My Business Page"
    }
  ]
}
FieldTypeDescription
itemsarrayList of subaccounts
items[].idstringSubaccount ID. Use this as target.pageId when publishing to Facebook or LinkedIn.
items[].accountIdstringParent account ID
items[].namestringName 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:

  1. Call GET /v2/users/me/accounts?platform=twitter (replace with your platform)
  2. Use items[].id as accountId in your publish request
  3. If multiple accounts are returned, use fullname or username to 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:

  1. Call GET /v2/users/me/accounts?platform=youtube
  2. Use items[].id as accountId
  3. Call GET /v2/users/me/accounts/{accountId}/subaccounts
  4. Use items[].id values as target.playlistIds in your publish request
  5. playlistIds is optional -- omit it to publish without adding to a playlist

Facebook

Facebook requires both accountId and pageId:

  1. Call GET /v2/users/me/accounts?platform=facebook
  2. Use items[].id as accountId
  3. Call GET /v2/users/me/accounts/{accountId}/subaccounts
  4. Use items[].id as target.pageId in your publish request
  5. If multiple pages are returned, use name to 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:

  1. Call GET /v2/users/me/accounts?platform=linkedin
  2. Use items[].id as accountId
  3. Call GET /v2/users/me/accounts/{accountId}/subaccounts
  4. Use items[].id as target.pageId
  5. If you skip pageId, the post goes to your personal LinkedIn profile

Pinterest

Pinterest requires a boardId. Fetch boards with the List Pinterest Boards endpoint:

  1. Call GET /v2/users/me/accounts?platform=pinterest
  2. Use items[].id as accountId
  3. Call GET /v2/social/pinterest/boards?accountId={accountId}
  4. Use items[].id as target.boardId in your publish request
  5. If multiple boards are returned, use name to 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

FieldTypeRequiredDescription
accountIdstringYesBlotato Pinterest account ID from GET /users/me/accounts.

Response

Status Code: 200 OK

{
  "items": [
    {
      "id": "1234567890123456789",
      "name": "Summer Outfits"
    }
  ]
}
FieldTypeDescription
itemsarrayList of Pinterest boards (max 250)
items[].idstringBoard ID. Use this as target.boardId when publishing a pin.
items[].namestringDisplay 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:

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

FieldTypeDescription
creditsRemainingintegerCredits left on the account.
accountEmailstringEmail of the account the API key belongs to.
purchaseQuantityRangeobjectAllowed purchase range, with min and max credits per purchase.
pricePer1000CreditsUsdnumberPrice in US dollars per 1,000 credits.

Example response:

{
  "creditsRemaining": 54688,
  "accountEmail": "user@example.com",
  "purchaseQuantityRange": { "min": 1000, "max": 10000 },
  "pricePer1000CreditsUsd": 6.0
}

Errors

StatusReason
401Missing or invalid API key.
500Server 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

FieldTypeRequiredDescription
quantityintegerYesCredits to buy. Between 1,000 and 10,000.
referralstringNoOptional referral code.

Response

Status Code: 201 Created

FieldTypeDescription
checkoutUrlstringStripe 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

StatusReason
400The quantity is outside the 1,000 to 10,000 range, or the request body is invalid.
401Missing or invalid API key.
429Rate limit exceeded (10 requests per hour).
500Server 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

FieldTypeRequiredDescription
urlstring✅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:

CodeDescription
90009Blotato could not fetch the media URL. Confirm the URL loads or downloads without signing in, then try again.
9999Unknown 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

FieldTypeRequiredDescription
filenamestringYesFilename 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 in mediaUrls when 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

  1. Fetch your connected accounts: GET /v2/users/me/accounts (docs)
  2. Fetch your subaccounts to get pageId for Facebook/LinkedIn and playlistIds for YouTube: GET /v2/users/me/accounts/{accountId}/subaccounts (docs).
  3. For a social platform, set content.platform and target.targetType to the same value (e.g., both "twitter"). The webhook target uses other and webhook.

Request Body

The request body has two top-level fields: post (required) and optional scheduling fields. Do not nest scheduling fields inside post.

FieldTypeRequiredDescription
postobjectYesThe post content and metadata.
scheduledTimestringNoISO 8601 timestamp with timezone offset for the requested future time. Use this without useNextFreeSlot: true.
useNextFreeSlotbooleanNoSchedule 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 scheduledTime is set, it supplies the publish time. Setting useNextFreeSlot: true as well still runs slot validation and fails when no matching slot is available. Do not combine the fields.
  • If useNextFreeSlot is true (and no scheduledTime): the post is scheduled at the next available calendar slot matching the destination.
  • If neither scheduledTime nor useNextFreeSlot is provided: the post publishes immediately.
  • Both fields must be root-level (siblings of post). If they are nested inside post, options, or any other object, they are ignored and the post publishes immediately.

post Object

FieldTypeRequiredDescription
accountIdstringYesThe account ID from GET /v2/users/me/accounts.
contentobjectYesThe content of the post. See content below.
targetobjectYesThe target platform and platform-specific fields. See target below.

content Object

FieldTypeRequiredDescription
textstringYesThe text content of the post.
mediaUrlsarray of stringsYesArray of media URLs. Pass any publicly accessible URL -- no upload step required. Pass [] for text-only posts.
platformstringYesFor social platforms, match target.targetType. Use other for the webhook target. Values: twitter, linkedin, facebook, instagram, pinterest, tiktok, threads, bluesky, youtube, other
additionalPostsarrayNoAdditional 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

PlatformtargetTypeRequired FieldsOptional Fields
Twitter"twitter"(none)(none)
LinkedIn"linkedin"(none)pageId
Facebook"facebook"pageIdmediaType, link, firstComment
Instagram"instagram"(none)mediaType, altText, collaborators, coverImageUrl, shareToFeed, audioName, trial, firstComment
TikTok"tiktok"privacyLevel, disabledComments, disabledDuet, disabledStitch, isBrandedContent, isYourBrand, isAiGeneratedtitle, autoAddMusic, isDraft, imageCoverIndex, videoCoverTimestamp
Pinterest"pinterest"boardIdtitle, altText, link
Threads"threads"(none)replyControl
Bluesky"bluesky"(none)(none)
YouTube"youtube"title, privacyStatus, shouldNotifySubscribersisMadeForKids, containsSyntheticMedia, playlistIds, thumbnailUrl
Webhook"webhook"url(none)

Twitter

FieldTypeRequired
targetType"twitter"Yes

LinkedIn

FieldTypeRequiredDescription
targetType"linkedin"Yes
pageIdstringNoLinkedIn 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.

Facebook

FieldTypeRequiredDescription
targetType"facebook"Yes
pageIdstringYesFacebook Page ID from subaccounts.
mediaType"reel" or "story"See descriptionVideo 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.
linkstringNoURL to attach as a link preview.
firstCommentstringNoAuto-posts this text as the first comment right after the post publishes. Up to 8000 characters. Works on feed posts and reels, not Stories.

Instagram

FieldTypeRequiredDescription
targetType"instagram"Yes
mediaType"reel" or "story"NoDefault: "reel" for videos. Set "story" to publish one image or video as an Instagram Story.
altTextstringNoAlt text for images. Up to 1000 characters.
collaboratorsarray of stringsNoInstagram 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.
coverImageUrlstringNoCover image URL for reels. Max 8MB.
shareToFeedbooleanNoShare the reel to the Instagram feed. Only applies to reels.
audioNamestringNoCustom audio name for reels. You can only set this once per reel.
trialobjectNoSettings for trial reels. Trial reels are shown to non-followers first. Only applies to reels. See trial object below.
firstCommentstringNoAuto-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

FieldTypeRequiredDescription
graduationStrategystringYes"MANUAL" (you promote to followers manually) or "SS_PERFORMANCE" (Instagram auto-promotes based on performance).

TikTok

FieldTypeRequiredDescription
targetType"tiktok"Yes
privacyLevelstringYesSELF_ONLY, PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, or FOLLOWER_OF_CREATOR
disabledCommentsbooleanYes
disabledDuetbooleanYes
disabledStitchbooleanYes
isBrandedContentbooleanYesSet true only for a paid partnership with a third-party brand. Adds TikTok's paid-partnership disclosure. Set false for organic content.
isYourBrandbooleanYesSet true when the post promotes your own brand, product, or business. This drives TikTok's "Promotional content" disclosure. Set false for organic content.
isAiGeneratedbooleanYesSet true when the content is AI-generated. This drives TikTok's AI-generated label. Set false for content you filmed or made yourself.
titlestringNoTitle for image posts. Max 90 characters. No effect on videos.
autoAddMusicbooleanNoAdd music to photo posts. No effect on videos. Default: false.
isDraftbooleanNoPost as a draft. Drafts appear in TikTok mobile app notifications, not the Drafts folder.
imageCoverIndexnumberNoIndex (starting from 0) of image to use as cover for carousels.
videoCoverTimestampnumberNoTimestamp 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.

Pinterest

FieldTypeRequiredDescription
targetType"pinterest"Yes
boardIdstringYesPinterest Board ID. Get from List Pinterest Boards.
titlestringNoPin title.
altTextstringNoPin alt text.
linkstringNoPin URL link.

Pinterest "description" comes from the content.text field.

Threads

FieldTypeRequiredDescription
targetType"threads"Yes
replyControlstringNoeveryone, accounts_you_follow, or mentioned_only

Bluesky

FieldTypeRequired
targetType"bluesky"Yes

YouTube

FieldTypeRequiredDescription
targetType"youtube"Yes
titlestringYesVideo title.
privacyStatusstringYesprivate, public, or unlisted
shouldNotifySubscribersbooleanYes
isMadeForKidsbooleanNoDefault: false
containsSyntheticMediabooleanNoWhether media contains AI-generated content.
playlistIdsarray of stringsNoYouTube playlist IDs to add the video to. Get from subaccounts.
thumbnailUrlstringNoPublicly 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.

FieldTypeRequiredDescription
targetType"webhook"Yes
urlstringYesThe webhook URL to send the post data.

Response

Status Code: 201 Created

{
  "postSubmissionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "scheduledTime": "2025-03-10T15:30:00Z"
}
FieldTypeDescription
postSubmissionIdstringID of the post submission. Use it to poll Get Post Status for publishing progress.
scheduledTimestringThe 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

FieldTypeRequiredDescription
postSubmissionIdstringYesThe 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

FieldTypeDescription
postSubmissionIdstringThe post submission ID.
statusstringOne of: in-progress, scheduled, published, failed.
scheduledTimestringThe scheduled publish time. Present when status is scheduled.
publicUrlstringURL returned for a published result, when available. The field is optional.
errorMessagestringDescription of the failure. Present when status is failed.

Polling Strategy

  1. Wait at least 10 seconds between status requests.
  2. Continue while status is in-progress, within a defined attempt or elapsed-time limit. Verify the ID came from the original create response.
  3. If status is scheduled, report the returned scheduledTime and stop this polling loop. Scheduling is confirmed, not publication.
  4. Stop when status is published (success) or failed (error).
  5. On failed, inspect errorMessage and 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

FieldTypeRequiredDescription
sincestringNoOnly include posts whose post time is on or after this ISO 8601 timestamp. Defaults to 7 days ago.
untilstringNoOnly include posts whose post time is on or before this ISO 8601 timestamp. Defaults to 7 days from now.
limitintegerNoNumber of items per page. Min: 1, Max: 250. Default: 50.
cursorstringNoPagination cursor from a previous response. Pass it to fetch the next page.
statusstring[]NoFilter by status. One or more of scheduled, published, failed. Pass multiple values to include any of them. Omit to include all statuses.
platformstring[]NoFilter 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

FieldTypeDescription
itemsarrayList of posts within the time window, ordered by postTime descending.
items[].idstringThe 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[].postTimestringISO 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[].platformstringSocial media platform.
items[].textstringThe post text.
items[].mediaUrlsstring[]URLs of attached media (images, video). Empty when text-only.
items[].accountobject or nullConnected account with id, name, and subaccount. Null if the account is no longer connected.
items[].stateobjectDiscriminated union; see below.
cursorstringPagination 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 }
FieldTypeDescription
postUrlstring | nullThe live URL of the published post. Null if the platform did not return one.
analyticsobject | nullLatest 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" }
FieldTypeDescription
errorMessagestring | nullHuman-readable description of the failure.

Errors

StatusReason
422Invalid 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

FieldTypeRequiredDescription
querystringNoFull-text search over post content. Omit to include all posts.
platformstringNoFilter to one platform. Omit to include all platforms.
sortBystringNoSort order: newest or oldest. Default newest.
offsetintegerNoNumber of posts to skip before the page. Default 0.
limitintegerNoNumber 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
}
FieldTypeDescription
itemsarrayPublished posts for this page.
items[].idstringThe published post id. Pass it to Get Post Analytics for full metric history.
items[].contentstringThe post text.
items[].postUrlstring or nullLive URL of the published post. Null if the platform did not return one.
items[].platformstringSocial media platform.
items[].createdAtstringISO 8601 timestamp when the post was published.
items[].mediaUrlsstring[]URLs of attached media. Empty when text-only.
items[].latestMetricsobjectThe most recent metrics snapshot. Absent if no metrics have been collected yet. See Metrics.
items[].metricsHistoryarrayCollected snapshots, oldest first. Each is { fetchedAt, metrics }.
countintegerTotal 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

StatusReason
422Invalid 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:

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.

PlanCheckpoints per postCollection windowCadence
Starter430 daysDay 1, then days 7, 14, and 30
Creator1830 days2 hours, daily through day 8, then every 2-3 days through day 30
Agency2090 days2 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.

  1. Check the platform and plan against the supported metrics.
  2. Check whether the post was published through Blotato with analytics enabled.
  3. Compare the post's age with its plan's checkpoints.
  4. Inspect lastError and the account's connection state. Reconnect when authorization is missing or expired, not as a repeated generic fix.
  5. 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

FieldTypeRequiredDescription
sincestringNoOnly include posts published on or after this ISO 8601 timestamp. Defaults to 30 days ago.
untilstringNoOnly include posts published on or before this ISO 8601 timestamp. Defaults to now.
platformstringNoFilter 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.
sortBystringNoMetric 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.
limitintegerNoNumber 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

FieldTypeDescription
itemsarrayPublished 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[].idstringThe published post id. Pass this to Get Post Analytics.
items[].contentstringThe post text.
items[].postUrlstring | nullLive URL of the published post. Null if the platform did not return one.
items[].platformstringSocial media platform.
items[].createdAtstringISO 8601 timestamp when the post was published.
items[].mediaUrlsstring[]URLs of attached media. Empty when text-only.
items[].latestMetricsobjectThe most recent metrics snapshot. Absent if no metrics have been collected yet. See Metrics.
items[].metricsHistoryarrayAll collected snapshots, oldest first. Each is { fetchedAt, metrics }.

Errors

StatusReason
422Invalid 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.

FieldTypeRequiredDescription
sincestringNoInclude posts published on or after this ISO 8601 timestamp. Defaults to 24 hours ago.
untilstringNoInclude posts published on or before this ISO 8601 timestamp. Defaults to now.
bucketstringNoTime 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.

FieldTypeRequiredDescription
sincestringNoInclude posts published or failed on or after this ISO 8601 timestamp. Defaults to 30 days ago.
untilstringNoInclude posts published or failed on or before this ISO 8601 timestamp. Defaults to now.
bucketstringNoTime 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

FieldTypeRequiredDescription
idstringYesThe 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

FieldTypeDescription
publishedPostIdstringThe id of the published post.
platformstringSocial media platform.
lastFetchedAtstring | nullISO 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.
lastErrorstring | nullThe last error Blotato hit while fetching metrics for this post, if any.
metricsobject | nullLatest metrics snapshot. See Metrics and Empty vs null metrics.
historyarrayAll collected snapshots, oldest first. Each is { fetchedAt, metrics }.

Errors

StatusReason
404No 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 id used 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 null for 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.

FieldTypeDescriptionStarterCreatorAgency
viewsCountstringViews.✓✓✓
impressionsCountstringImpressions.✓✓✓
reachCountstringUnique accounts reached.✓✓✓
likesCountstringLikes.✓✓✓
commentsCountstringComments.✓✓✓
repliesCountstringReplies.✓✓✓
sharesCountstringShares.✓✓✓
savesCountstringSaves / bookmarks.✓✓✓
clicksCountstringLink or content clicks.✓✓✓
followsCountstringFollows gained from the post.✓✓✓
playsCountstringVideo / audio plays.✓✓✓
profileVisitsCountstringProfile visits driven by the post.✓✓✓
profileActivityCountstringProfile actions driven by the post.✓✓✓
navigationsCountstringIn-post navigation actions (e.g. carousel swipes).✓✓✓
interactionsSumstringTotal interactions.✓✓✓
viewTimeMsSumstringTotal watch time, milliseconds.✓✓✓
watchTimeMsAvgstringAverage watch time, milliseconds.✓✓✓

Twitter / X

Post-level metrics.

FieldTypeDescriptionStarterCreatorAgency
twitterRetweetsCountstringRetweets.✓✓✓
twitterQuotesCountstringQuote tweets.✓✓✓

Per-media video metrics. Each is an array indexed by media position in the post; null entries mark non-video media.

FieldTypeDescriptionStarterCreatorAgency
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.

FieldTypeDescriptionStarterCreatorAgency
blueskyRepostsCountstringReposts.✓✓✓
blueskyQuotesCountstringQuote posts.✓✓✓

Threads

Post-level metrics.

FieldTypeDescriptionStarterCreatorAgency
threadsRepostsCountstringReposts.✓✓✓
threadsQuotesCountstringQuote posts.✓✓✓

Facebook

Post-level metrics.

FieldTypeDescriptionStarterCreatorAgency
facebookPostMediaViewsCountstringMedia views on the post.✓✓
facebookPostMediaViewsUniqueCountstringUnique media views on the post.✓✓
facebookPostReactionsByTypeobjectReactions broken down by type (e.g. like, love, haha).✓✓

Video and Reels metrics.

FieldTypeDescriptionStarterCreatorAgency
facebookBlueReelsPlaysCountstringReel plays.✓✓
facebookFbReelsReplaysCountstringReel replays.✓✓
facebookFbReelsTotalPlaysCountstringTotal reel plays (plays plus replays).✓✓
facebookPostVideoWatchTimeMsAvgstringAverage video watch time, milliseconds.✓✓
facebookPostVideoFollowersCountstringFollowers gained from the video.✓✓
facebookPostVideoLikesByReactionTypeobjectVideo likes broken down by reaction type.✓✓
facebookPostVideoSocialActionsByTypeobjectVideo social actions broken down by type.✓✓
facebookPostVideoViewTimeMsSumstringTotal video view time, milliseconds.✓✓
facebookTotalVideoViewsCountstringTotal video views.✓✓
facebookTotalVideoViewsUniqueCountstringUnique video views.✓✓
facebookTotalVideoViewsAutoplayedCountstringAutoplayed video views.✓✓
facebookTotalVideoViewsClickedToPlayCountstringClick-to-play video views.✓✓
facebookTotalVideoViewsSoundOnCountstringVideo views with sound on.✓✓
facebookTotalVideoCompleteViewsCountstringComplete video views.✓✓
facebookTotalVideoCompleteViewsUniqueCountstringUnique complete video views.✓✓
facebookTotalVideoCompleteViewsAutoplayedCountstringAutoplayed complete video views.✓✓
facebookTotalVideoCompleteViewsClickedToPlayCountstringClick-to-play complete video views.✓✓
facebookTotalVideoCompleteViewsOrganicCountstringOrganic complete video views.✓✓
facebookTotalVideoCompleteViewsOrganicUniqueCountstringUnique organic complete video views.✓✓
facebookTotalVideoCompleteViewsPaidCountstringPaid complete video views.✓✓
facebookTotalVideoCompleteViewsPaidUniqueCountstringUnique paid complete video views.✓✓
facebookTotalVideoViews10sCountstringVideo views of at least 10 seconds.✓✓
facebookTotalVideoViews10sUniqueCountstringUnique 10-second video views.✓✓
facebookTotalVideoViews10sAutoplayedCountstringAutoplayed 10-second video views.✓✓
facebookTotalVideoViews10sClickedToPlayCountstringClick-to-play 10-second video views.✓✓
facebookTotalVideoViews10sOrganicCountstringOrganic 10-second video views.✓✓
facebookTotalVideoViews10sPaidCountstringPaid 10-second video views.✓✓
facebookTotalVideoViews10sSoundOnCountstring10-second video views with sound on.✓✓
facebookTotalVideoViews15sCountstringVideo views of at least 15 seconds.✓✓
facebookTotalVideoViews60sExcludesShorterCountstringVideo views of at least 60 seconds (excludes shorter).✓✓
facebookTotalVideoWatchTimeMsAvgstringAverage total video watch time, milliseconds.✓✓
facebookTotalVideoViewTimeMsSumstringTotal video view time, milliseconds.✓✓
facebookTotalVideoViewTimeOrganicMsSumstringOrganic video view time, milliseconds.✓✓
facebookTotalVideoViewTimePaidMsSumstringPaid video view time, milliseconds.✓✓
facebookTotalVideoStoriesByActionTypeobjectVideo stories (shares/comments/etc.) broken down by action type.✓✓
facebookTotalVideoReactionsByTypeobjectVideo reactions broken down by type.✓✓
facebookTotalVideoViewTimeMsByAgeBucketAndGenderobjectVideo view time broken down by age bucket and gender.✓✓
facebookTotalVideoViewTimeMsByRegionIdobjectVideo view time broken down by region.✓✓
facebookTotalVideoViewsByDistributionTypeobjectVideo views broken down by distribution type.✓✓

LinkedIn

Post-level metrics.

FieldTypeDescriptionStarterCreatorAgency
linkedinFirstLevelCommentsCountstringFirst-level comments (excludes replies).✓✓✓
linkedinReactionsByTypeobjectReactions broken down by type (e.g. like, praise, empathy).✓✓

Pinterest

Post-level metrics.

FieldTypeDescriptionStarterCreatorAgency
pinterestPinClicksCountstringPin clicks.✓✓
pinterestReactionsCountstringReactions.✓✓✓
pinterestVideoP95ViewsCountstringVideo views reaching 95% of the video.✓✓
pinterestVideo10sViewsCountstringVideo views of at least 10 seconds.✓✓
pinterestVideoMrcViewsCountstringMRC-standard video views.✓✓
pinterestVideoV50WatchTimeMsSumstringWatch time for views past 50%, milliseconds.✓✓
pinterestSaveRatenumberSaves 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.

FieldTypeDescriptionStarterCreatorAgency
youtubeDislikesCountstringDislikes.✓✓
youtubeSubscribersLostCountstringSubscribers lost from the video.✓✓
youtubeVideosAddedToPlaylistsCountstringTimes the video was added to a playlist.✓✓
youtubeVideosRemovedFromPlaylistsCountstringTimes the video was removed from a playlist.✓✓
youtubeRedViewsCountstringYouTube Premium (Red) views.✓✓
youtubeRedViewTimeMsSumstringYouTube Premium (Red) watch time, milliseconds.✓✓
youtubeEngagedViewsCountstringEngaged views.✓✓
youtubeAverageViewPercentagenumberAverage percentage of the video watched, 0–100.✓✓
youtubeCardClicksCountstringCard clicks.✓✓
youtubeCardImpressionsCountstringCard impressions.✓✓
youtubeCardClickRatenumberCard clicks divided by impressions, a 0–1 ratio.✓✓
youtubeCardTeaserClicksCountstringCard teaser clicks.✓✓
youtubeCardTeaserImpressionsCountstringCard teaser impressions.✓✓
youtubeCardTeaserClickRatenumberCard teaser clicks divided by impressions, a 0–1 ratio.✓✓
youtubeAnnotationClicksCountstringAnnotation clicks.✓✓
youtubeAnnotationClickableImpressionsCountstringClickable annotation impressions.✓✓
youtubeAnnotationClosesCountstringAnnotation closes.✓✓
youtubeAnnotationClosableImpressionsCountstringClosable annotation impressions.✓✓
youtubeAnnotationImpressionsCountstringAnnotation impressions.✓✓
youtubeAnnotationClickThroughRatenumberAnnotation click-through rate, a 0–1 ratio.✓✓
youtubeAnnotationCloseRatenumberAnnotation close rate, a 0–1 ratio.✓✓

Related


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:

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.


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

FieldTypeRequiredDescription
limitintegerNoMaximum comments to return (1-250). Default 50.
cursorstringNoCursor from a previous response. Pass it to fetch the next page.
platformarrayNoFilter by platform. Values: instagram, facebook.
accountIdstringNoFilter to a single connected account.
parentCommentIdstringNoFilter to direct replies to a single comment.
postIdstringNoFilter to comments on a single post using its Blotato post ID.
sincestringNoOnly include comments created on or after this ISO 8601 timestamp.
untilstringNoOnly 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..."
}
FieldTypeDescription
itemsarrayList of comments. See Comment Object.
cursorstringCursor 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

FieldTypeRequiredDescription
commentIdstringYesBlotato 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!"
}
FieldTypeRequiredDescription
postIdstringYesBlotato 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.
textstringYesPlain-text comment body. Instagram allows up to 2200 characters, Facebook up to 8000.
parentCommentIdstringNoBlotato 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

StatusReason
404The published post or parent comment was not found, or comments are not enabled for your account.
422The 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).
429Rate 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

FieldTypeDescription
idstringBlotato comment ID.
accountIdstringID of the connected account the comment belongs to.
platformstringinstagram or facebook.
postIdstring or nullBlotato 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.
parentCommentIdstring or nullBlotato ID of the parent comment when this comment is a reply. null for top-level comments.
platformPostIdstringSocial platform (e.g. Instagram) ID of the parent post.
platformCommentIdstring or nullSocial platform (e.g. Instagram) ID of the comment.
authorIdstring or nullSocial platform (e.g. Instagram) ID of the comment author.
authorobjectWho 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.
isAuthorbooleantrue when your connected account authored the comment. false for an audience reply.
textstringComment text.
statusstringComment status. See Status Values.
errorCodeinteger or nullSet only when status is failed. See Comments Errors.
errorMessagestring or nullSet only when status is failed.
createdAtstringISO 8601 timestamp when the comment was created.

Status Values

StatusMeaning
queuedAccepted and waiting to post.
processingPosting to the social platform.
postedLive on the social platform.
failedDid not post. See errorMessage.
deletedRemoved from the social platform.

Rate Limits

EndpointLimit
GET /comments60 / min
GET /comments/:commentId60 / min
POST /comments30 / 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:

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.


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

FieldTypeRequiredDescription
limitintegerNoMaximum conversations to return (1-250). Default 50.
cursorstringNoCursor from a previous response. Pass it to fetch the next page.
platformstringNoFilter by platform. Values: instagram, facebook.
accountIdstringNoFilter 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..."
}
FieldTypeDescription
itemsarrayList of conversations. See Conversation Object.
cursorstringCursor 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

FieldTypeRequiredDescription
conversationIdstringYesBlotato 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

FieldTypeRequiredDescription
limitintegerNoMaximum messages to return (1-250). Default 50.
cursorstringNoCursor from a previous response. Pass it to fetch the next page.
conversationIdstringNoFilter to messages in a single conversation.
platformarrayNoFilter by platform. Values: instagram, facebook.
accountIdstringNoFilter 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..."
}
FieldTypeDescription
itemsarrayList of messages. See Message Object.
cursorstringCursor 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

FieldTypeRequiredDescription
messageIdstringYesBlotato 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"
  }
}
FieldTypeRequiredDescription
accountIdstringYesBlotato ID of the connected account the message is sent from.
recipientIdstringYesSocial platform (e.g. Instagram) ID of the recipient. Get it from an existing conversation or incoming message.
textstringYesPlain-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.
targetobjectYesWhere and how to send. See Target.

Target

FieldTypeRequiredDescription
targetTypestringYesValue: instagram or facebook.
pageIdstringFor FacebookID of the Facebook Page to send from, from subaccounts. Required when targetType is facebook.
commentIdstringNoBlotato comment ID. When set, Blotato delivers the message as a private reply to that comment instead of a direct message.
attachmentobjectNoUp to 3 call-to-action buttons pinned under the message. See Buttons and Quick Replies.
quickRepliesarrayNoUp to 13 tappable reply chips shown under the message. See Buttons and Quick Replies.
responseTypestringNoHow the message fits the platform's messaging window: RESPONSE, UPDATE, or MESSAGE_TAG. Default RESPONSE. See Messaging Windows.
tagstringNoRequired 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" }
      ]
    }
  }
}
FieldTypeRequiredDescription
typestringYesValue: button.
buttonsarrayYes1 to 3 buttons.

Each button has:

FieldTypeRequiredDescription
typestringYesweb_url opens a link. postback reports the tap back to you.
titlestringYesButton label, 1 to 20 characters.
urlstringFor web_urlLink the button opens. Starts with https://.
payloadstringFor postbackValue 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" }
    ]
  }
}
FieldTypeRequiredDescription
titlestringYesChip label, 1 to 20 characters.
payloadstringYesValue 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" }
  }
}
FieldValueMeaning
selection.typequick-replyThe person tapped a chip. text is the chip label.
selection.typepostbackThe person tapped a button you attached. text is the button label.
selection.payloadstring or nullThe 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 attachment and quickReplies. 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).
  • responseType is MESSAGE_TAG and you did not set tag.

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 RESPONSE within 24 hours of the contact's last message.
  • Private reply to a comment: set commentId on the target to reply once, within 7 days of the comment.
  • Outside the window: set responseType to MESSAGE_TAG with an approved tag (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

FieldTypeDescription
idstringBlotato conversation ID.
accountIdstringID of the connected account this conversation belongs to.
platformstringinstagram or facebook.
participantsarrayThe other people in the conversation. Each has id, name, username, and profileImageUrl, any of which may be null.
createdAtstringISO 8601 timestamp when the conversation started.
updatedAtstringISO 8601 timestamp of the most recent activity.

Message Object

FieldTypeDescription
idstringBlotato message ID.
conversationIdstring or nullBlotato ID of the parent conversation.
platformstringinstagram or facebook.
directionstringincoming for messages you receive, outgoing for messages you send.
senderIdstring or nullSocial platform (e.g. Instagram) ID of the sender.
recipientIdstringSocial platform (e.g. Instagram) ID of the recipient.
textstringMessage text.
payloadobject or nullRich content on the message. See Payload.
statusstringMessage status. See Status Values.
errorCodeinteger or nullSet only when status is failed. See Messaging Errors.
errorMessagestring or nullSet only when status is failed.
createdAtstringISO 8601 timestamp when the message was created.

Payload

payload is null on a plain-text message. Otherwise it holds one or more of:

FieldTypeDescription
attachmentobjectButtons you attached to an outgoing message. See Buttons.
quickRepliesarrayQuick-reply chips you attached to an outgoing message. See Quick Replies.
selectionobjectSet 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.

StatusMeaning
queuedAccepted and waiting to send.
processingSending to the social platform.
sentHanded to the social platform.
deliveredAn incoming message delivered to you.
failedDid not send. See errorMessage.

Rate Limits

EndpointLimit
GET /conversations60 / min
GET /conversations/:conversationId60 / min
GET /messages60 / min
GET /messages/:messageId60 / min
POST /messages30 / 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:

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 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

  1. Someone comments on your post or sends your account a message.
  2. Blotato matches the event against every active trigger on every live automation on the account.
  3. A match starts one run per matching automation. An automation with a comment trigger and a message trigger starts a single run per event.
  4. 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.
  5. 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.
  6. The run reaches completed, failed, expired, or superseded.

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:

  1. 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.
  2. 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.
  3. Your message (dmMessage plus buttons).
  4. 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

FieldTypeRequiredDescription
limitintegerNoMaximum automations to return (1-250). Default 50.
cursorstringNoCursor 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..."
}
FieldTypeDescription
itemsarrayList of automations. See DM Automation Object.
items[].statsobjectRun counts from the last 24 hours: triggered, completed, and failed, plus lastRunAt.
items[].stats.lastRunAtstring or nullISO 8601 time the automation last ran. Null when it has never run.
cursorstringCursor 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

FieldTypeRequiredDescription
idstringYesBlotato 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 emailGate to gate it behind the contact replying with an email address.
  • Set webhook to call an external endpoint once the message sends.
  • Set commentReply to change the public reply posted under the triggering comment. Omit it to turn on the default replies, or pass null to 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": []
  }
}
FieldTypeRequiredDescription
namestringNoNew automation label, 1-60 characters.
triggersarrayNoReplaces every trigger. Up to 2 triggers, at most one per type. Pass [] to remove every trigger. See Trigger Object.
dmMessagestringNoReplaces the message text, 1-640 characters.
buttonsarrayNoReplaces the buttons. Pass [] to remove every button.
followGateobject or nullNoReplaces the follow gate. Pass null to remove it. Instagram only. See Follow Gate Object.
emailGateobject or nullNoReplaces the email gate. Pass null to remove it. See Email Gate Object.
webhookobject or nullNoReplaces the webhook. Pass null to remove it. See Webhook Object.
commentReplyobject or nullNoReplaces the public reply. Pass null to turn it off. See Comment Reply Object.
isActivebooleanNotrue 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

FieldTypeRequiredDescription
flowIdstringYesBlotato ID of the automation.
triggerIdstringYesID of the trigger, from the automation's triggers array.

Request Body

The patch is nested under a patch key.

{
  "patch": { "isActive": false }
}
FieldTypeRequiredDescription
isActivebooleanYestrue 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

FieldTypeRequiredDescription
limitintegerNoMaximum runs to return (1-250). Default 50.
cursorstringNoCursor from a previous response. Pass it to fetch the next page.
statusstring[]NoInclude runs matching any supplied status: running, waiting, completed, expired, superseded, or failed. Omit to include every status.
sincestringNoInclude 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

FieldTypeRequiredDescription
flowRunIdstringNoInclude logs belonging to this run. Omit to include logs across every run.
limitintegerNoMaximum logs to return (1-250). Default 50.
cursorstringNoCursor 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
  }
}
FieldTypeDescription
triggeredintegerRuns started by a matching comment or message.
completedintegerRuns where every step finished.
failedintegerAll-time runs ending on an error.
issuesintegerRuns 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

FieldTypeDescription
idstringBlotato automation ID.
accountIdstringID of the connected account the automation runs on.
namestringAutomation label.
platformstringinstagram or facebook.
targetobjectSee Target.
triggersarrayTriggers the automation listens for, up to 2. Empty on a draft with no triggers. See Trigger Object.
dmMessagestringMessage text sent when a trigger fires.
buttonsarrayLink buttons attached to the message. See Button Object.
followGateobjectFollow gate on the automation. Absent when no follow gate is set. See Follow Gate Object.
emailGateobjectEmail gate on the automation. Absent when no email gate is set. See Email Gate Object.
webhookobjectWebhook on the automation. Absent when no webhook is set. See Webhook Object.
commentReplyobjectPublic reply posted under the triggering comment. Absent when the public reply is off. See Comment Reply Object.
isActivebooleantrue when the automation is live and listening.
publishedVersionIdstring or nullID of the published version. null for a draft.
createdAtstringISO 8601 timestamp when the automation was created.
updatedAtstringISO 8601 timestamp of the most recent edit.

Target

FieldTypeRequiredDescription
targetTypestringYesinstagram or facebook.
pageIdstringFor FacebookID 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.

FieldTypeRequiredDescription
idstringRead-onlyBlotato trigger ID. Present on every trigger Blotato returns. Omit it when you create or update an automation. Pass it to Update DM Automation Trigger.
typestringYescomment-received or message-received. A comment-received trigger fires on top-level comments only, and skips replies to comments.
keywordsarrayYesWords 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.
postIdstring or nullNoComment 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.
isActivebooleanNofalse 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

FieldTypeRequiredDescription
typestringYesurl. Link buttons are the only type buttons accepts.
titlestringYesButton label, up to 20 characters.
urlstringYes to publishhttp(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.

FieldTypeRequiredDescription
messagestringYesGate message text, 1-640 characters. Blotato sends it with a confirm button under it.
buttonTitlestringNoLabel 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 message to 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.

FieldTypeRequiredDescription
messagestringYesGate 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.

FieldTypeRequiredDescription
variantsarrayYes3 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 @username on 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 dmMessage behind 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.

FieldTypeRequiredDescription
methodstringYesGET, POST, PUT, PATCH, or DELETE.
urlstringYesPublic http(s) endpoint, 1-2048 characters.
headersobjectNoString 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 }
FieldTypeDescription
emailstring or nullEmail address on file for the contact, captured by an email gate. null when Blotato holds none.
isFollowerboolean or nullFollower 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.

RuleBehavior
AddressThe host must resolve to a public address. Private, loopback, link-local, and cloud metadata ranges return error code 20304.
Protocolhttp and https only.
RedirectsBlotato does not follow them. Point the automation at the final URL.
Timeout15 seconds. A timeout logs a warning with error code 20305, the run still completes, and Blotato does not retry the request.
Response bodyBlotato reads the first 16 KB.
Error responseA non-2xx status gets logged with its status, and the run still completes.
FailureA blocked address, a DNS failure, or a connection error fails the run with error code 20304.
HeadersRedacted 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

FieldTypeDescription
idstringBlotato run ID. Pass it as flowRunId to List Logs.
contactIdstringSocial platform ID of the person who triggered the run.
platformstringinstagram or facebook.
statusstringSee Run Status Values.
errorobjectSet only when status is failed. Holds code, message, and, when available, action and details with recovery context.
createdAtstringISO 8601 timestamp when the run started.
updatedAtstringISO 8601 timestamp of the most recent run update.

Run Status Values

StatusMeaning
runningExecuting a step.
waitingWaiting for the DM to settle, or waiting on the contact to answer a gate.
completedEvery step finished, including the DM.
expiredThe 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.
supersededA newer run started waiting on the same contact, so this one stopped.
failedThe run stopped on an error, either before or after the DM went out. Read error.

Log Object

FieldTypeDescription
idstringBlotato log ID.
flowRunIdstringID of the run this log belongs to.
nodeIdstring or nullID of the step the log came from. null for run-level entries.
levelstringinfo, warning, or error.
messagestringDescription of the step.
contextobjectStep-specific details, for example the message ID.
createdAtstringISO 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

StatusReason
404The 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.
422The 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}}.
500Unexpected 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

EndpointLimit
GET /dm-automations60 / min
GET /dm-automations/:id60 / min
POST /dm-automations30 / min
PATCH /dm-automations/:id30 / min
PATCH /dm-automations/:flowId/triggers/:triggerId30 / min
DELETE /dm-automations/:id30 / min
GET /dm-automations/:id/runs60 / min
GET /dm-automations/:id/logs60 / min
GET /dm-automations/:id/analytics60 / 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

ValueRequiresDescription
youtubeurlExtract YouTube transcript (English captions only)
tiktokurlExtract TikTok transcript (English captions only)
articleurlExtract article text from a web page
pdfurlExtract text from a PDF
audiourlTranscribe audio (mp3, wav, m4a, ogg, flac, aac)
twitterurlExtract tweet content
texttextTransform raw text content with optional AI instructions
perplexity-querytextAI-powered web research query

Parameters

ParameterTypeRequiredDescription
source.sourceTypestringYesOne of: youtube, tiktok, article, pdf, audio, twitter, text, perplexity-query
source.urlstringRequired for URL-based typesThe URL to extract content from
source.textstringRequired for text and perplexity-queryRaw text or search query
customInstructionsstringNoAI 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

  1. In n8n, select Source > Create.
  2. Save the returned id.
  3. Use Source > Get to check the saved ID until status is completed or failed.
  4. Read content after completed, or report message after failed.

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

ParameterTypeRequiredDescription
idstringYesThe 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

StatusDescription
queuedSource submitted, waiting to process
processingExtraction in progress
completedExtraction successful, content available
failedExtraction failed, check message field

Polling Pattern

Source extraction is asynchronous. After calling Create Source:

  1. Wait at least 10 seconds
  2. Call Get Source with the ID
  3. If status is queued or processing, wait and retry
  4. If status is completed, use the content field
  5. If status is failed, check the message field

n8n and Make.com

In the official Blotato nodes:

  1. Add a Blotato node
  2. Select "Source" > "Get"
  3. Pass in the source ID from "Create Source"
  4. Add a Wait node of at least 10 seconds between status checks
  5. 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

  1. Choose a template from the categories below
  2. Retrieve the template through blotato_list_design_templates or GET /v2/videos/templates.
  3. Copy its exact id into templateId. Some IDs are UUIDs and others are paths. Do not shorten a path.
  4. Send a POST request to /v2/videos/from-templates with inputs: {}, a prompt, and render: 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.

TemplateIDContent inputOutput
Image Slideshow with Text Overlays/base/v2/image-slideshow/5903b592-1255-43b4-b9ac-f8ed7cbf6a5f/v1inputs.slides (objects)Slideshow
Instagram Carousel Slideshow53cfec04-2500-41cf-8cc1-ba670d2c341ainputs.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.

TemplateIDOutput
Quote Card with Monocolor Background/base/v2/quote-card/77f65d2b-48cc-4adb-bfbb-5bc86f8c01bd/v1Slideshow
Quote Card with Paper Background and Highlight/base/v2/quote-card/f941e306-76f7-45da-b3d9-7463af630e91/v1Slideshow

Tweet Cards

Twitter/X-style quote cards with minimal or photo/video backgrounds.

TemplateIDOutput
Tweet Card with Minimal Style/base/v2/tweet-card/ba413be6-a840-4e60-8fd6-0066d3b427df/v1Slideshow
Tweet Card with Photo/Video Background/base/v2/tweet-card/9714ae5c-7e6b-4878-be4a-4b1ba5d0cd66/v1Slideshow

Tutorial Carousels

Step-by-step tutorial visuals with customizable styling.

TemplateIDOutput
Tutorial Carousel with Minimalist Flat Style/base/v2/tutorial-carousel/2491f97b-1b47-4efa-8b96-8c651fa7b3d5/v1Slideshow
Tutorial Carousel with Monocolor Background/base/v2/tutorial-carousel/e095104b-e6c5-4a81-a89d-b0df3d7c5baf/v1Slideshow

Images with Text

Combine images and text overlays in various styles.

TemplateIDOutput
Image Slideshow with Prominent Text/base/v2/images-with-text/0ddb8655-c3da-43da-9f7d-be1915ca7818/v1Slideshow
When X then Y Text Slideshow/base/v2/images-with-text/c9892c3b-fa75-4ade-821a-a50ff8456230/v1Video
Video of Images and Text with Minimal Style/base/v2/images-with-text/3ed4bb92-dbfe-45e6-9dc8-605b77f70506/v1Video

Video Editor

Combine and edit video clips with titles, captions, and music.

TemplateIDOutput
Combine Clips and Apply Basic Edits/base/v2/combine-clips/c306ae43-1dcc-4f45-ac2b-88e75430ffd8/v1Video

AI Videos

AI-powered video generation with voiceovers and narration.

TemplateIDOutput
AI Video with AI Voice/base/v2/ai-story-video/5903fe43-514d-40ee-a060-0d6628c5f8fd/v1Video
AI Selfie Talking Video with Consistent Character/base/v2/ai-selfie-video/57f5a565-fd17-458b-be43-4a2d8ccaca75/v1Video

AI Avatar

AI avatar videos with generated B-roll footage.

TemplateIDOutput
AI Avatar with AI Generated B-roll/base/v2/ai-avatar-broll/7c26a1cd-d5b3-42da-9c73-2413333873b3/v1Video

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

TemplateIDOutput
TV Wall Infographic/video-template/013904bf-6b3b-43f4-bb1f-f1964a38c29bImage
Newspaper Infographic/video-template/07a5b5c5-387c-49e3-86b1-de822cd2dfc7Image
Breaking News/video-template/8800be71-52df-4ac7-ac94-df9d8a494d0fImage
Movie Theater Infographic/video-template/b88c8273-6406-48c6-85e7-096119aefe30Image

Urban and Street

TemplateIDOutput
Graffiti Mural Infographic/video-template/3598483b-c148-4276-a800-eede85c1c62fImage
Bus Ad Infographic/video-template/f9c0e470-9288-4958-8cdd-64772ed93c05Image
Billboard Infographic/video-template/76b3b959-bdbe-440d-8428-984219353f18Image

Education

TemplateIDOutput
Classroom Chalkboard Infographic/video-template/d9495026-3945-44f6-8b44-07c28c492e6dImage
Whiteboard Infographic/video-template/ae868019-820d-434c-8fe1-74c9da99129aImage
Chalkboard Infographic/video-template/fcd64907-b103-46f8-9f75-51b9d1a522f5Image

Outdoor

TemplateIDOutput
Trail Marker Infographic/video-template/29ebb2bd-02b7-4317-8bb8-c30eb938e47cImage
Constellation Infographic/video-template/5307053e-046b-4c9b-b1ca-38725d2ddcddImage

Creative

TemplateIDOutput
Manga Panel Infographic/video-template/49c61370-a706-4b82-98f7-62d557d1c66dImage
T-Shirt Infographic/video-template/476f8920-8749-4ff7-9c91-470d54c3c03eImage
Futuristic Flyer/video-template/8fa8545e-8955-4a89-a868-cf45023d6cc5Image
Book Page Infographic/video-template/f8f1ebe4-a9f5-4ec8-be63-21214656cd4bImage
Single Centered Text Quote/video-template/9f4e66cd-b784-4c02-b2ce-e6d0765fd4c0Slideshow

Tech

TemplateIDOutput
Steampunk Infographic/video-template/7b7104f1-d277-4993-ad3a-e5883c4b776dImage
Top Secret Infographic/video-template/b8707b58-a106-44af-bb12-e30507e561afImage

Historical

TemplateIDOutput
Egyptian Hieroglyph Infographic/video-template/a7b0d128-8478-4b34-9647-a0778b6517d0Image
Cave Painting Infographic/video-template/82ee75b6-597b-43a8-86bc-e4395e7c9c44Image

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:

  1. Browse available templates at my.blotato.com/videos/new
  2. In n8n or Make, replace the old node with the Blotato "Create Visual" node
  3. Select your template from the dropdown (start with a carousel — it renders in seconds)
  4. Open the Logs to inspect the exact JSON payload each template expects
  5. 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

FieldTypeRequiredDescription
templateIdstring✅The ID of the template to use. Get available templates from the /v2/videos/templates endpoint.
inputsobject✅Template-specific input parameters. Structure depends on the selected template. Can be an empty object {} if using the prompt parameter.
isDraftboolean❌Save as draft without rendering. Default: false.
promptstring❌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.
renderboolean❌Whether to render the visual immediately. Default: true.
titlestring❌A human-readable title for the generated video.
useBrandKitboolean❌Default: false. With a nonempty prompt, includes compiled brand context during template input generation. Requires a configured brand. See Brand Kit.
brandIdstring | 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:

FieldTypeDescription
fieldsstringComma-separated list of fields to include. Use id,name,description,inputs to get full template details.
searchstringCase-insensitive text search in template name or description. Characters are matched literally. Ignored when id is supplied.
idstringOptional 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.

  1. Call blotato_list_design_templates with {"search":"AI Video with AI Voice"}, or send the REST lookup below.
  2. Match the result to the requested output.
  3. Retain its complete id.
  4. Read its inputs specification for field names, nested types, defaults, allowed values, and limits.
  5. 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:

TemplateContent inputs
AI Video with AI Voicescenes, each with script and mediaSource
Image Slideshow with Text Overlaysslides, each with imageSource and optional textOverlay
Instagram Carousel SlideshowslidePrompts, where each entry is an image prompt string
Quote Card with Monocolor Backgroundtitle 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 TypeDescription
Image SlideshowCreate slideshows from images with text overlays
Instagram Carousel SlideshowAI-generated image carousels from text prompts
Quote CardGenerate quote cards with stylized backgrounds
Tweet CardCreate visual cards from tweet-style content
Tutorial CarouselStep-by-step tutorial visuals
AI Story VideoAI-generated story videos with narration
Combine ClipsMerge multiple video clips

Template Input Types

Templates use various input types:

TypeDescriptionExample
textPlain text string"Hello world"
numberNumeric value42
booleanTrue/falsetrue
enumChoice from predefined values"top" | "center" | "bottom"
imageImage URL"https://example.com/image.jpg"
videoVideo URL"https://example.com/video.mp4"
colorHex color code"#FF5733"
arrayList of items[{...}, {...}]
objectNested 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 processed
  • generating-script - AI is generating the script
  • script-ready - Script is ready, generating media
  • generating-media - Media is being generated
  • media-ready - Media is ready, exporting
  • exporting - Final export in progress
  • done - Complete. Use mediaUrl or imageUrls from 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

FieldTypeRequiredDescription
idstringYesThe video/visual ID returned by Create Visual

Response

Status Code: 200 OK

Status Values

StatusDescription
queueingRequest is queued. Keep polling.
generating-scriptAI is generating the script. Keep polling.
script-readyScript is ready, generating media. Keep polling.
generating-mediaMedia is being generated. Keep polling.
media-readyMedia is ready, exporting. Keep polling.
exportingFinal export in progress. Keep polling.
doneComplete. mediaUrl and/or imageUrls are available.
creation-from-template-failedCreation 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 in mediaUrls when publishing.
  • imageUrls: Array of image URLs (for slideshows/carousels). Use these in mediaUrls when 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:

FieldTypeRequiredDescription
idstring✅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

FieldTypeRequiredDescription
limitintegerNoNumber of items per page. Min: 1, Max: 50. Default: 20.
cursorstringNoPagination 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..."
}
FieldTypeDescription
itemsarrayList of scheduled posts
items[].idstringSchedule ID. Use this for get, update, and delete operations.
items[].scheduledAtstringISO 8601 UTC timestamp for when the post will publish.
items[].accountobject or nullThe target social account. Null if the account was disconnected.
items[].draftobjectThe post payload. Same structure as the post object in Publish Post.
countstringTotal number of future scheduled posts.
cursorstringPagination 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

FieldTypeRequiredDescription
idstringYesSchedule 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

FieldTypeRequiredDescription
idstringYesSchedule 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"
      }
    }
  }
}
FieldTypeRequiredDescription
patch.scheduledTimestringNoNew ISO 8601 timestamp. Must be in the future.
patch.draftobjectNoUpdated 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

StatusReason
404Schedule not found
422Empty 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

FieldTypeRequiredDescription
idstringYesSchedule ID from the List Scheduled Posts endpoint.

Response

Status Code: 204 No Content

Errors

StatusReason
404The 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

  1. Slots define your posting cadence -- for example, "every Monday at 9:00 AM UTC for Twitter."
  2. 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.
  3. A slot is "occupied" when a scheduled post is already queued at that time. The next call to useNextFreeSlot skips occupied slots and picks the next open one.
  4. 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
        }
      ]
    }
  ]
}
FieldTypeDescription
items[].idstringSlot ID
items[].hourintegerHour in UTC (0-23)
items[].minuteintegerMinute (0-59)
items[].daystringDay of week: monday, tuesday, wednesday, thursday, friday, saturday, sunday
items[].selectedTargetsarrayPlatforms and accounts this slot applies to
items[].selectedTargets[].platformstringPlatform name
items[].selectedTargets[].accountIdstring or nullAccount ID. Null means the slot applies to all accounts on that platform.
items[].selectedTargets[].subaccountIdstring or nullSubaccount 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
        }
      ]
    }
  ]
}
FieldTypeRequiredDescription
slotsarrayYesArray of slots to create
slots[].hourintegerYesHour in UTC (0-23)
slots[].minuteintegerYesMinute (0-59)
slots[].daystringYesDay of week (e.g., monday)
slots[].selectedTargetsarrayYesPlatforms 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

FieldTypeRequiredDescription
idstringYesSlot 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

FieldTypeRequiredDescription
idstringYesSlot ID

Response

Status Code: 204 No Content

Errors

StatusReason
400Slot 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
}
FieldTypeRequiredDescription
platformstringYesPlatform name
accountIdstringNoAccount ID. Omit to match slots for all accounts on the platform.
subaccountIdstringNoSubaccount ID for Facebook Pages / LinkedIn Company Pages.

Response

Status Code: 201 Created

{
  "slot": {
    "slotId": "slot_1",
    "slotTime": "2026-04-02T09:00:00Z"
  }
}
FieldTypeDescription
slot.slotIdstringThe slot that was matched
slot.slotTimestringISO 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

FieldUse
mediaTypeOptional reel or story. Choose the format requested by the user.
collaboratorsOptional array of Instagram usernames without @.
altTextOptional image description.
coverImageUrlOptional public Reel cover URL.
shareToFeedOptional boolean for also sharing a Reel to the main feed.
audioNameOptional name for the Reel's original audio.
trialOptional trial Reel settings. Read the publish schema before setting graduationStrategy.
firstCommentOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
pageIdRequired Facebook Page ID.
mediaTypeOptional reel or story for the media format.
linkOptional URL for a link preview.
firstCommentOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
privacyLevelRequired: SELF_ONLY, PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, or FOLLOWER_OF_CREATOR.
disabledComments, disabledDuet, disabledStitchRequired booleans for interaction settings.
isBrandedContent, isYourBrand, isAiGeneratedRequired booleans describing the content.
titleOptional image-post title.
autoAddMusicOptional music setting for image posts.
isDraftOptional draft submission instead of direct publication.
imageCoverIndex, videoCoverTimestampOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
titleRequired title, up to 100 characters. Do not include < or >.
privacyStatusRequired: private, public, or unlisted.
shouldNotifySubscribersRequired boolean.
isMadeForKidsOptional audience declaration.
containsSyntheticMediaOptional synthetic-media declaration.
thumbnailUrlOptional public custom-thumbnail URL. Account verification requirements apply.
playlistIdsOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
pageIdOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
boardIdRequired board ID from the board lookup.
titleOptional title, up to 100 characters.
altTextOptional image description, up to 500 characters.
linkOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
additionalPostsOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
replyControlOptional: everyone, accounts_you_follow, or mentioned_only.
additionalPostsOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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

FieldUse
additionalPostsOptional 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

  1. Save the returned postSubmissionId.
  2. If processing continues, use blotato_get_post_status or GET /v2/posts/:postSubmissionId.
  3. 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.

  1. Call the CREATE endpoint. Record the ID from the 201 response (id for sources, item.id for videos, postSubmissionId for posts). A scheduled post also returns scheduledTime, the resolved UTC publish time.
  2. Check the GET endpoint at least 10 seconds apart for posts and sources, and at least 15 seconds apart for visuals.
  3. Continue polling while status is processing (see status values below).
  4. Stop on a terminal result. Report success only for the operation's success state, not for a failure or draft.
  5. 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) or failed
  • Videos: done (success), creation-from-template-failed, insufficient-credits, or any response with item.error. A draft is not a rendered result.
  • Posts: published (success), failed, or scheduled for 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 -> done

Always fetch accounts first: GET /v2/users/me/accounts to get accountId for publishing. To get pageId for Facebook/LinkedIn or playlistIds for YouTube, also fetch GET /v2/users/me/accounts/{accountId}/subaccounts.

For social platforms, set content.platform and target.targetType to the same value (e.g., both "twitter"). The REST webhook target uses other with webhook.

Content Calendar: GET /v2/schedules to list scheduled posts. PATCH /v2/schedules/:id to update content or time. DELETE /v2/schedules/:id to cancel. GET /v2/schedule/slots for 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 a url field)
  • text - Transform raw text content with optional AI instructions
  • perplexity-query - AI-powered web research on any topic (requires a text field)
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 to GET /v2/posts/{postSubmissionId} with your Blotato credential. Do not assume all integration versions expose the same operations.

[!IMPORTANT] Prerequisites:

  1. accountId: Get this from GET /v2/users/me/accounts. Always fetch the user's accounts before publishing. See Accounts reference.
  2. pageId: Required for Facebook Pages and LinkedIn company Pages. Omit it for a LinkedIn personal-profile post. Get it from GET /v2/users/me/accounts/{accountId}/subaccounts. See How to Get the Right IDs.
  3. mediaUrls: Use existing accessible media URLs, or mediaUrl and imageUrls from 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.
  4. content.platform and target.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:

  1. Slots define recurring time windows (e.g., "Monday 9 AM for Twitter"). Create them with POST /v2/schedule/slots.
  2. When you publish with useNextFreeSlot: true, Blotato finds the next open slot matching the target platform and queues the post at that time.
  3. A slot is "occupied" when a scheduled post is already queued at that time. The next useNextFreeSlot call skips occupied slots.
  4. 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 scheduledAt for the publish time. The update endpoint accepts scheduledTime as 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:

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.