exepal_
exepal / tools / social-media-posting-api

Post everywhere your agent can reach, for a tenth of a cent.

Send the text, optional images and up to four accounts, each with its own credentials. Exepal posts to each network, turns long text into a thread of replies where the network has threads, and tells you what went where. The formatter takes the same draft and makes it ready for X, Bluesky, Threads, Mastodon, LinkedIn, Facebook, Instagram, TikTok, YouTube, Pinterest, Telegram and Discord, without posting anything.

What you get back

  • Publish to Bluesky (handle + app password), Mastodon (server + access token), Telegram (bot token + chat id) and Discord (channel webhook) in one call
  • Up to 4 images with alt text; Bluesky links, #tags and @mentions made clickable
  • Long text split into a numbered thread of replies, or rejected if you set thread to false
  • Per network: ok, link to the post, every post id, or the reason it failed (credentials are never echoed)
  • Formatter: length counted each platform's way (Bluesky graphemes, X weighted characters and 23-character links), hashtag caps (Instagram 5, Threads 1, YouTube 15), thread split or word-boundary trim, warnings

Call it from your code or agent

Same input and the same JSON answer everywhere. You're only charged when the call succeeds.

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

curl -X POST https://api.exepal.com/v1/social/format \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"text":"We just shipped pay-per-call social posting for agents.","platforms":["x","bluesky","threads"],"hashtags":["agents"]}'

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

const res = await fetch("https://api.exepal.com/v1/social/format", {
  method: "POST",
  headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_KEY" },
  body: JSON.stringify({
    "text": "We just shipped pay-per-call social posting for agents.",
    "platforms": [
      "x",
      "bluesky",
      "threads"
    ],
    "hashtags": [
      "agents"
    ]
  }),
});
const data = await res.json();

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

import requests

r = requests.post(
    "https://api.exepal.com/v1/social/format",
    headers={"Authorization": "Bearer YOUR_KEY"},
    json={
        "text": "We just shipped pay-per-call social posting for agents.",
        "platforms": [
            "x",
            "bluesky",
            "threads"
        ],
        "hashtags": [
            "agents"
        ]
    },
    timeout=120,
)
print(r.json())

Add Exepal once and your assistant can call social_publish by itself. More clients on the integrate page.

# Claude Code
claude mcp add --transport http exepal "https://api.exepal.com/mcp?key=YOUR_KEY"

# Cursor, Windsurf, Claude Desktop and most clients (mcp.json)
{
  "mcpServers": {
    "exepal": { "url": "https://api.exepal.com/mcp?key=YOUR_KEY" }
  }
}

No key at all: an agent with a wallet pays per call in USDC on Base. npm i @x402/fetch @x402/evm viem. How x402 works.

import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

const pay = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(privateKeyToAccount(process.env.WALLET_KEY)) }],
});
const res = await pay("https://api.exepal.com/v1/social/format", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "text": "We just shipped pay-per-call social posting for agents.",
    "platforms": [
      "x",
      "bluesky",
      "threads"
    ],
    "hashtags": [
      "agents"
    ]
  }),
});

MCP tool names: social_publish, social_format.

Questions

Do you store my passwords or tokens?
No. They are used for that one request and dropped. They are not cached, not logged and scrubbed from any error message. For Bluesky use an app password, never your main password, and revoke it any time.
Why not X, Instagram, Facebook, LinkedIn or TikTok?
Those networks only let approved apps post on a user's behalf, through their own review processes. Until Exepal's apps are approved there, use social_format to prepare the text and post with the tools you already have.
Am I charged if a post fails?
You pay once per call, only when at least one network accepted the post. If every network refuses it, the call fails and nothing settles.
Can it schedule posts?
Not yet. Your agent decides when to call; the post goes out immediately.

Related tools