Last updated: September 2026
Schedule a Claude routine to post to X, Bluesky and LinkedIn
Create a Claude Code routine with a weekly schedule. Its prompt writes the week's posts and sends them in one request to POST https://opentweet.io/api/v1/posts, each with a scheduled_date and platforms. OpenTweet then publishes every post on time, even if a later routine run fails. Allow opentweet.io in the routine's cloud environment first.
Most guides stop at "tell the routine to post to X". The part that breaks in practice is the sandbox: routines block unknown hosts by default, and your local MCP servers do not come along. This page covers both, plus a daily publish-now variant.
7-day free trial. Cancel anytime. $11.99/mo after.
Daily publish or weekly batch?
A routine is a saved prompt that Anthropic runs on a schedule in a cloud session. You can have it publish once a day, or run once a week and let OpenTweet's scheduler do the publishing.
| Daily, publish_now | Weekly, scheduled_date per post | |
|---|---|---|
| Routine runs | 7 a week, or 5 on the weekdays preset | 1 a week |
| If a run fails or is skipped | That day gets no post | The week is already queued in OpenTweet and publishes on time |
| Review before it goes out | None. publish_now sends it straight away | Every post sits in your OpenTweet queue for days. Edit or delete any of them |
| Duplicate check | Built in: a single post that matches one you posted or scheduled returns 409 | Not applied to multi-post requests. The prompt reads your recent posts instead |
| Retries | Idempotency-Key per day stops a second post that day | Idempotency-Key per week stops a second batch that week |
| Best for | News or metrics that change daily | Evergreen and planned content, which is most of it |
The weekly batch is the one to start with. It uses one routine run instead of seven, and the posts are already in OpenTweet before the first one is due.
1. Connect your accounts and get a key
Sign up, connect X, Bluesky and LinkedIn in Settings, and generate an API key in the API section. It starts with ot_. No X developer account or LinkedIn developer app is needed.
2. Let the cloud environment reach OpenTweet
Every routine runs in a cloud environment. The Default one uses Trusted network access, which only lets through a fixed list of package registries and development domains. opentweet.io is not on it, so a plain curl fails with 403 and x-deny-reason: host_not_allowed. Pick one of these.
Pro and Max: add the key as an API credential
Open the routine's environment settings (the cloud icon below the Instructions box, then the settings icon), find API credentials, and select Add credential. Keep the type Bearer, set Allowed websites to opentweet.io, leave the header as Authorization with prefix Bearer, and paste your ot_ key as the value.
Anthropic's proxy then adds the key to every request for opentweet.io after it leaves the session, and the host becomes reachable even on Trusted. Claude never sees the key, which is why the prompts on this page send no Authorization header.
Team and Enterprise: environment variable plus allowlist
API credentials are not available on Team or Enterprise yet. Add the key under Environment variables:
OPENTWEET_API_KEY=ot_your_key_here
Then set Network access to Custom, list the hosts one per line in Allowed domains, and tick Also include default list of common package managers if the routine installs anything:
opentweet.io mcp.opentweet.io
Add -H "Authorization: Bearer $OPENTWEET_API_KEY" to each curl in the prompt. Anthropic notes that anyone who uses the environment can read its variables, so use a dedicated environment and a key you can revoke. Shared organization environments are changed by an Owner in admin settings.
Changes apply from the next run
New variables and network settings reach sessions started after you save. A run already in progress keeps the old values.3. Create the weekly routine
Go to claude.ai/code/routines and click New routine, or run /schedule in the Claude Code CLI (it needs a claude.ai subscription login). Add a small GitHub repository that holds voice.md (how you write) and topics.md (what to write about); the routine clones it on every run. Select the environment from step 2, choose the Weekly preset, and pick a time such as Sunday 18:00. Times are in your local zone.
Paste this as the prompt:
You are my social media manager. This routine runs once a week and plans
the next five weekdays of posts. OpenTweet publishes them; you only write
and schedule them.
1. Read voice.md and topics.md in this repository.
2. See what already went out or is queued, so you do not repeat yourself:
curl -s "https://opentweet.io/api/v1/posts?status=posted&limit=50"
curl -s "https://opentweet.io/api/v1/posts?status=scheduled&limit=50"
Do not reuse a topic or an opening line from either list.
3. Write 10 posts: Monday to Friday of the coming week, at 09:00 and 16:00
America/New_York. Each post under 280 characters. No links.
4. Send all 10 in ONE request. Convert each time to UTC ISO 8601.
curl -s -w "\n%{http_code}" -X POST https://opentweet.io/api/v1/posts \
-H "Content-Type: application/json" \
-H "Idempotency-Key: week-<ISO year>-<ISO week number>" \
-d '{"platforms": ["x", "bluesky", "linkedin"],
"posts": [
{"text": "...", "scheduled_date": "2026-09-28T13:00:00Z"},
{"text": "...", "scheduled_date": "2026-09-28T20:00:00Z"}
]}'
5. If the status is not 201, print the status and the body and stop.
Do not rewrite the posts and send them again.
6. Finish with a table: post id, scheduled time, first 60 characters.
Authentication: the environment attaches my OpenTweet key to requests for
opentweet.io, so do not add an Authorization header.Why one request: POST /api/v1/posts accepts a posts array of up to 50, and a top-level platforms applies to each post that does not set its own. OpenTweet validates the whole batch before creating anything, so one invalid post means none are created.
Why the Idempotency-Key: OpenTweet stores a successful response against the key for 24 hours. If the same batch is sent again within that window, the second call replays the first response. If a second run writes different posts under the same key, it gets 422 idempotency_key_reused instead of a second week of posts. Failed requests are not stored, so a fixed retry still goes through.
Remove connectors you do not need. Every connector on your account is added to a new routine by default, and Claude can use all of their tools, including writes, without asking.
Click Run now once, open the run, and check for a 201 and ten ids. The posts should then show in your OpenTweet queue.
The daily publish-now variant
Use a Daily or Weekdays trigger when the post depends on that day's data. A single-post request runs OpenTweet's duplicate check: if the text matches something you already posted or scheduled, you get 409 with duplicate_content instead of a repeat.
You post one update a day for me on X, Bluesky and LinkedIn.
1. Read voice.md and topics.md in this repository.
2. curl -s "https://opentweet.io/api/v1/posts?status=posted&limit=20"
and do not repeat a topic or opening line from it.
3. Write one post under 280 characters. No links.
4. Publish it:
curl -s -w "\n%{http_code}" -X POST https://opentweet.io/api/v1/posts \
-H "Content-Type: application/json" \
-H "Idempotency-Key: day-<YYYY-MM-DD>" \
-d '{"text": "...", "platforms": ["x", "bluesky", "linkedin"], "publish_now": true}'
5. If the status is 409 with duplicate_content, write a clearly different
post and try once more. On any other error, print it and stop.
6. Print posts[0].results so I can see the outcome on each network.The response carries one entry per network in posts[0].results. A post over Bluesky's 300 characters is skipped on Bluesky with a reason while X and LinkedIn still publish.
Using the MCP server instead of curl
MCP servers you added with claude mcp add stay on your machine and do not reach routines. There are two ways to give a routine the OpenTweet tools.
A committed .mcp.json
A routine with exactly one repository loads that repository's .mcp.json, without the approval prompt you see locally. Claude Code expands ${VAR} in headers, so the key stays in the environment variable from step 2 and out of git:
{
"mcpServers": {
"opentweet": {
"type": "http",
"url": "https://mcp.opentweet.io/mcp",
"headers": { "Authorization": "Bearer ${OPENTWEET_API_KEY}" }
}
}
}Anthropic's docs only exempt claude.ai connectors from the network allowlist, so keep mcp.opentweet.io in Allowed domains for this route. Then replace step 4 of the weekly prompt with:
For each post, call opentweet_create_tweet with: text, platforms: ["x", "bluesky", "linkedin"], scheduled_date (UTC ISO 8601) Before writing, call opentweet_list_tweets to see what is already scheduled and posted, and do not repeat it.
opentweet_batch_schedule also exists, but it schedules posts that already exist as drafts, so creating each post with its scheduled_date is one step shorter.
A claude.ai custom connector
Connectors travel through Anthropic's servers, so they need no allowlist entry, and they are what Cowork scheduled tasks use. The catch: OpenTweet's hosted server authenticates with Authorization: Bearer ot_... and has no OAuth, and Anthropic lists request-header auth for custom connectors as beta, entered by an organization administrator. If the Request headers section appears when you add a custom connector at claude.ai/customize/connectors, enter https://mcp.opentweet.io/mcp with the header value Bearer ot_your_key. If it does not, use one of the routes above.
Routine limits to know
From Anthropic's routines and cloud environment docs, as of September 2026.
| Plans with routines | Pro, Max, Team and Enterprise. Team and Enterprise Owners can switch routines off for everyone. |
| Where to create them | claude.ai/code/routines, the Desktop app (Routines, then Cloud), or /schedule in the Claude Code CLI |
| Shortest interval | One hour. Presets are hourly, daily, weekdays and weekly; set custom cron with /schedule update |
| Runs per day | A daily cap per account on top of normal subscription usage. The docs do not publish the number; your remaining runs show at claude.ai/code/routines |
| One-off runs | Do not count against the daily routine cap |
| Default network | Trusted: a fixed allowlist of package registries and dev domains. opentweet.io is not on it |
| Secrets | API credentials (key hidden from Claude) on Pro and Max only. Team and Enterprise use environment variables, which anyone using the environment can read |
| Status | Research preview. Behavior, limits and the API surface may change |
Claude Cowork has its own scheduled tasks, on all paid plans. Type /schedule in a Cowork task or open Scheduled in the sidebar; cadences are hourly, daily, weekly, weekdays or manual. They use your connected tools, so they reach OpenTweet only through the custom connector above.
Guardrails before you leave it running
Always pass platforms
A post with no platforms value follows the account auto cross-post setting, which can mean every connected network. An explicit array is honoured exactly.
One bad post fails the whole batch
If x is a target and any post is over your X character limit, the request returns 400 validation_failed and nothing is created. Ask for under 280 characters unless you have X Premium.
The batch counts against today
Scheduling checks how many posts your plan can still publish today: 20 on Pro, 100 on Advanced, 300 on Agency. Keep a weekly batch under that, at most 50 posts per request, and under 300 queued posts in total.
Links cost allowance
Pro includes no link posts per day; Advanced includes 10 and Agency 20. Over the allowance OpenTweet strips the URL from the text. Tell the routine "no links" unless your plan covers them.
Want a human check?
Leave out scheduled_date and the posts are saved as drafts. They wait in the OpenTweet dashboard until you schedule or delete them.
Read the transcript, not the green dot
Anthropic notes that a green run status only means the session exited cleanly. Blocked requests and API errors show up inside the run, which is why the prompt prints the status code.
LinkedIn specifics
LinkedIn posts go to your personal profile only. The LinkedIn sign-in lasts 60 days with no refresh, so OpenTweet emails you to reconnect and holds scheduled LinkedIn posts until you do. Hashtags and @mentions publish as plain text there.Frequently asked questions
Can a Claude routine post to X every day automatically?
Yes. Create a routine with a daily schedule trigger whose prompt writes a post and sends it to OpenTweet's POST /api/v1/posts with publish_now set to true. The routine runs in Anthropic's cloud, so your laptop can be closed. A more reliable setup is one weekly routine that schedules the whole week in OpenTweet, so a missed run does not mean a missed post.
Why does my routine get a 403 host_not_allowed when it calls opentweet.io?
The Default cloud environment uses Trusted network access, which only allows a fixed list of package registries and development domains. Either add your OpenTweet key as an API credential for opentweet.io (Pro and Max), which also makes the host reachable, or switch the environment's network access to Custom and add opentweet.io and mcp.opentweet.io to Allowed domains.
Will my routine see the MCP servers I added with claude mcp add?
No. Those live in ~/.claude.json on your machine. A routine gets the connectors on your claude.ai account, plus servers declared in a committed .mcp.json when the routine has exactly one repository.
How often can a routine run?
At most once an hour. Anthropic rejects cron expressions that run more often. There is also a daily cap on routine runs per account, which the docs do not state as a number; claude.ai/code/routines shows how many you have left.
Can Claude post to LinkedIn and Bluesky from a routine too?
Yes. Put "linkedin" and "bluesky" in the platforms array next to "x". LinkedIn posts go to your personal profile; Company Pages are not supported. Each network reports its own result, so a post over Bluesky's 300 characters is skipped there while X and LinkedIn still publish.
Does this work with Claude Cowork scheduled tasks?
The same prompt works. Cowork scheduled tasks are created with /schedule in a Cowork task or from Scheduled in the sidebar, run hourly, daily, weekly or on weekdays, and use your connected tools. Cowork reaches OpenTweet through a connector, so it depends on adding the hosted MCP server as a custom connector with an Authorization request header, which Anthropic lists as beta.
Can I approve posts before they publish?
Yes. Drop scheduled_date from each post and OpenTweet saves them as drafts. You then schedule, edit or delete them in the dashboard. The weekly batch also gives you days to change anything that is already scheduled.
Keep exploring
Interactive Claude setups, the MCP server and the API reference.
Claude Cowork as a social media manager
The interactive version: drafting and scheduling from a Cowork chat.
Post to X from Claude Code
Add the OpenTweet MCP server to your local Claude Code.
Can Claude Code post to LinkedIn?
What works on a personal profile and what does not.
Twitter MCP server
The hosted server with 43 tools for X, Bluesky and LinkedIn.
REST API reference
Every field on POST /api/v1/posts, including threads and media.
Give any agent a posting tool
The same endpoint as a tool for LangChain, CrewAI and more.
One routine a week, posts every day
Claude writes the week. OpenTweet publishes it to X, Bluesky and LinkedIn on schedule.
7-day free trial. Cancel anytime.