Papera is still under development. Things may change or break as we build.
MCPExample: one post, every account

Example: one post, every account

Turn a content node into a social post, tailor it per platform, wire it to your accounts and publish it, with the confirmation step in full.

You have a project with content in it, and you want one post out of that content on Bluesky and Telegram, worded a little differently on each. This is the run from content node to live posts.

You need: an AI client connected to Papera, a project with a content node in it (see a deck from your notes), and the accounts already connected in the app (see Connect a Bluesky account and Connect a Telegram channel).

The ids below are shortened for readability.

1. See what is there

You: Take the launch note in my Papera project and post it to Bluesky and Telegram.

// get_workflow
{ "project_id": "9c1f2a84", "workflow_id": "41ac7d20" }

The graph comes back: one content node, content-3b71, and nothing rendered from it yet.

2. Make the post

// attach_renderer
{
  "project_id": "9c1f2a84",
  "workflow_id": "41ac7d20",
  "source_node_id": "content-3b71",
  "renderer_id": "social-post"
}

social-post is the platform-neutral post: one post that can go to any account. The call returns the post node id, output-77e0, and the content it derived from your content node.

3. Tailor it per platform

Bluesky has a tight character limit and Telegram does not, so give Bluesky its own caption and let Telegram inherit the shared default:

// edit_post
{
  "project_id": "9c1f2a84",
  "workflow_id": "41ac7d20",
  "post_node_id": "output-77e0",
  "variants": {
    "bluesky": {
      "caption": "Scheduling is live. Pick a time, pick the accounts, done.",
      "hashtags": ["papera", "shipit"]
    }
  }
}

A variant overrides only the fields it sets, so Telegram still gets the shared default. Hashtags are written without the leading #.

4. Point it at your accounts

Add a node for each connected account, using the connection_id from the app:

// add_node
{ "project_id": "9c1f2a84", "workflow_id": "41ac7d20", "kind": "account", "connection_id": "conn-bsky-01" }
// add_node
{ "project_id": "9c1f2a84", "workflow_id": "41ac7d20", "kind": "account", "connection_id": "conn-tg-01" }

Then wire the post to both in one call:

// target_accounts
{
  "project_id": "9c1f2a84",
  "workflow_id": "41ac7d20",
  "post_node_id": "output-77e0",
  "account_node_ids": ["account-a1", "account-b2"]
}

Each account is handled on its own. If one cannot take the post, it comes back in rejected with the reason and the other still connects.

5. Add the trigger that fires it

Publishing is done by a trigger, so add one and wire it to the post:

// add_node
{ "project_id": "9c1f2a84", "workflow_id": "41ac7d20", "kind": "trigger" }
// connect_nodes
{
  "project_id": "9c1f2a84",
  "workflow_id": "41ac7d20",
  "from_node_id": "trigger-c3",
  "to_node_id": "output-77e0"
}

6. Read the plan before anything goes out

// publish_post
{ "project_id": "9c1f2a84", "workflow_id": "41ac7d20", "post_id": "output-77e0" }

Nothing is posted by this call. Papera returns a plan and a token, and your client shows you the plan:

Papera: This fires trigger trigger-c3. 1 post to 2 accounts: the launch note to @you.bsky.social (bluesky, 1 image) and to Papera News (telegram, 1 image). Publishing also replaces the saved snapshot with the current draft.

Read it as written: confirming fires the whole trigger, so every post that trigger reaches goes out, not only the one you named. Here that is the one post.

7. Confirm

// publish_post
{
  "project_id": "9c1f2a84",
  "workflow_id": "41ac7d20",
  "post_id": "output-77e0",
  "confirm_token": "ct_5b9e..."
}

The token works once, expires after ten minutes, and is tied to these exact arguments. Change an argument and you get a fresh plan instead.

8. Follow it

// get_publish_status
{ "project_id": "9c1f2a84", "occurrence_id": "manual:trigger-c3" }

Accounts appear as each one concludes, with a link to the live post on success and the reason on failure. Your client polls until both are listed. Re-running the same fire does not post twice.

Variations

More accounts. Add a node per connection and pass them all to target_accounts in one call.

Every platform tailored. Give each platform its own entry in variants: instagram, bluesky, telegram, linkedin.

Part of the content only. Put a transformer between the content node and the post with attach_transformer and section_ids, so the post renders from the sections you pick.

Later, not now. Instead of publish_post, arm the trigger on a schedule. See a post every week.