Developers · agents
Post from your code — or your agent
One API key opens a REST API and an MCP server. Both run the exact validation the composer runs — the same character limits, the same per-platform rules — so an agent cannot send what the app would refuse. Keys are created under Account → API keys. Included in the $5 per connected account / month; no add-on.
MCP — connect an agent
Endpoint https://castacross.com/mcp (Streamable HTTP, POST). Tools: list_accounts, create_post, list_posts, delete_post, get_upload_url.
Claude Code
claude mcp add --transport http castacross https://castacross.com/mcp --header "Authorization: Bearer cp_your_key"
Cursor / Windsurf / any MCP client
{
"mcpServers": {
"castacross": {
"url": "https://castacross.com/mcp",
"headers": { "Authorization": "Bearer cp_your_key" }
}
}
}Claude.ai · ChatGPT · any connector directory
Add a custom connector with the URL https://castacross.com/mcp — nothing else. The client registers itself, sends you to https://castacross.com/oauth/authorize, you sign in and press Allow; tokens rotate on their own. Header keys still work everywhere a header can be set.
Then say: "Post this video to TikTok, Instagram Reels and YouTube Shorts with the same caption, tomorrow at 9." The agent lists your accounts, builds the post per platform and reports each target's link.
REST API
Base https://castacross.com/v1. Send the key as Authorization: Bearer cp_your_key. JSON in, JSON out.
GET /v1/accounts
curl https://castacross.com/v1/accounts -H "Authorization: Bearer cp_your_key"
→ { accounts: [{ id, platform, username, needs_reconnect, followers }] }
POST /v1/posts
curl -X POST https://castacross.com/v1/posts \
-H "Authorization: Bearer cp_your_key" -H "Content-Type: application/json" \
-d '{
"content": "Three lighting mistakes and the $40 fix for each.",
"account_ids": ["acc_instagram", "acc_youtube"],
"media_urls": ["https://…/clip.mp4"],
"mode": "schedule",
"scheduled_for": "2026-09-01T09:00:00",
"timezone": "America/New_York",
"targets": [
{ "account_id": "acc_youtube", "settings": { "title": "3 lighting mistakes (and the $40 fix)", "visibility": "public" } },
{ "account_id": "acc_tiktok", "settings": { "privacy_level": "PUBLIC_TO_EVERYONE" } }
]
}' mode: now · schedule (+ scheduled_for, timezone) · queue (next free slot) · draft. targets[].settings takes the per-platform fields: TikTok privacy_level (required), allow_comment/duet/stitch; Reddit subreddit, title (required); Pinterest boardId, title, link; YouTube title, visibility, tags, madeForKids; Instagram contentType: "story"; firstComment on Instagram, LinkedIn, YouTube, Threads. recycling: { gap, gap_freq: "week"|"month", expire_count } reposts on a cycle. Returns 201 with the post, or 400 with a one-line reason.
GET /v1/posts · GET /v1/posts/:id · DELETE /v1/posts/:id
Status per target (scheduled · publishing · published · failed · partial · draft) and the live URL once published.
POST /v1/media/presign
curl -X POST https://castacross.com/v1/media/presign -H "Authorization: Bearer cp_your_key" \
-H "Content-Type: application/json" -d '{"filename":"clip.mp4","content_type":"video/mp4","size":18000000}'
# → { upload_url, public_url } then: curl -X PUT "$upload_url" -H "Content-Type: video/mp4" --data-binary @clip.mp4 Files go straight to storage (up to 5 GB); the public_url is what you pass as a media_url.
Limits and errors
- Every request is validated like the composer: X 280, Bluesky 300, Threads 500, Instagram/TikTok 2,200, LinkedIn 3,000, YouTube 5,000 characters; media required on Instagram, TikTok, YouTube, Pinterest; media count caps per platform.
401missing or revoked key ·400the reason inmessage·503publishing not configured.- No rate limit beyond the platforms' own; be reasonable. Revoke a key any time from the account page.