Give your product a publish button.
One dependency, and your product can schedule and publish to nine networks, then answer the replies that come back. No platform APIs to learn, and no tokens to keep alive.
import { Orbitwrite } from "@orbitwrite/sdk";
const orbit = new Orbitwrite({ apiKey: process.env.ORBITWRITE_API_KEY });
await orbit.posts.create({
channels: ["acc_x", "acc_li", "acc_bs"],
content: "Shipped something today.",
publishNow: true,
});Cancel anytime before the trial ends.
- One dependency
- Runs anywhere JavaScript does
- Typed end to end
What you don’t have to build
Publishing to social networks is weeks of work that never quite finishes, because the networks keep changing. It’s done.
Nine sets of API docs
One call reaches every network. Nothing in your code names any of them.
OAuth, and keeping it alive
Your users connect their channels here. Tokens are ours to hold, and your code never sees one.
Each network's rules
Lengths, media, formats. Checked before a post goes out, and refused with the reason when it can't.
A media pipeline
Attach an image or a video and we handle the rest, whatever the network will accept.
Deciding when to post
Ask for the next good time and get the one the workspace's own calendar would pick.
Getting retries right
Handled for you, and only where replaying can't publish something twice.
What it covers
Enough for a product to publish, follow up and answer the replies. Media, campaigns, tags, post approvals and webhooks are each a documented HTTP call away, on the same key.
Channels
The accounts your users have connected, and which of them can publish right now.
Posts
Write, schedule, move, publish and remove. One post can reach every channel at once.
Timing
The next good time to post, taken from the workspace's own schedule.
Outcomes
Where a post got to on each channel, and why, when a network turns one down.
Inbox
Replies and mentions from every channel. Answer them, snooze them, hand them to a teammate and resolve them.
Held replies
A reply that needs sign-off waits for an approver, and your code can release it or send it back.
await orbit.posts.create({
content: "Shipping today.",
channels: [
"acc_x",
{ accountId: "acc_li", content: "A longer take, for a slower feed." },
],
scheduledAt: slot.at,
});const [channel] = await orbit.channels.postable();
if (!channel) throw new Error("Connect a channel first.");
const slot = await orbit.schedule.nextTime(channel.id);
if (!slot) throw new Error("No free slot in the next two weeks.");
await orbit.posts.create({
channels: [channel.id],
content: "Scheduled by the app that wrote it.",
scheduledAt: slot.at,
});for await (const c of orbit.conversations.iterate({ status: "open", assignee: "unassigned" })) {
const thread = await orbit.conversations.get(c.id);
const result = await orbit.conversations.reply(c.id, { text: draftReply(thread) });
if (result.status === "sent") await orbit.conversations.resolve(c.id);
}The details
Your code, and your users’ agents, publishing while nobody is watching. Most of what follows is about that going wrong safely.
One call, every channel
Your product publishes where your users already are, without naming a single network.
Mistakes surface as you type
The client is generated from the API, so your editor catches what a network would have refused.
Same words, or different ones
Post once everywhere, or give a channel its own copy. Both stay one thing you can move.
The schedule your workspace keeps
Ask for the next good time and land exactly where the calendar says you will.
Refusals you can act on
Every no comes back with a reason your code can branch on, not a string to read.
Never published twice
Retries are handled for you, and only where replaying is safe.
Images and video come along
Attach a file and we check it against the network before anything goes out.
Approvals still hold
A post or reply your app creates waits for review like any other, and you can see where it got to.
Access you can take back
Each key is scoped to one workspace and to what you allow. Revoke it and everything stops.
The package is @orbitwrite/sdk, and the API under it is documented at orbitwrite.com/api/v1/docs. For a single post from a script there’s the CLI, which is this with argument parsing in front, and for an agent to drive the workspace itself, the MCP server.