Narrareach connectors
Copy page
Open Markdown
Open in ClaudeOpen in ChatGPT

Connect Narrareach to Claude, ChatGPT, Gemini, Notion Agents, and MCP clients.

Narrareach exposes a secure MCP endpoint for LLM apps. Users connect with OAuth and approve access without handling client secrets or private credentials. The connector supports writer workflows across Substack, Medium, LinkedIn, X, Bluesky, Threads, Instagram, Facebook, TikTok, and Pinterest.
Start here

How the connector works

Narrareach uses the Model Context Protocol over HTTPS. Claude, ChatGPT, Gemini, and Notion Agents discover the endpoint, register an OAuth client dynamically, send the user through Narrareach sign-in, and authorize future MCP requests. MCP is included on paid plans with scheduling and analytics.
One URL
Users provide /mcp. The client discovers the rest.
OAuth
Users grant permissions through Narrareach. No shared secrets are exposed.
DCR + PKCE
Dynamic client registration and PKCE S256 handle client setup safely.
Claude

Connect the official Narrareach connector

Narrareach is an official Claude connector. In Claude, open Connectors, find Narrareach, select Connect, and complete Narrareach sign-in.
If Narrareach isn't listed for your account, add it as a custom connector with the values below. Leave Advanced settings closed. Claude registers the OAuth client automatically.
Name
Narrareach
Connector URL
https://www.narrareach.com/mcp
Claude custom connector form with Narrareach and the connector URL filled in
ChatGPT

Connect the official Narrareach plugin

Open Narrareach in ChatGPT
  1. Open the official Narrareach listing and install the plugin.
  2. Connect your account when prompted. Sign in with the same email you use for Narrareach and review the requested permissions.
  3. In a new chat, type @ and select Narrareach. Ask it to show your connected accounts and existing drafts before scheduling.

On a phone or tablet, open the listing in your browser if you cannot find it in the app. Availability can depend on your ChatGPT account and workspace settings.

If Substack asks for a verification code and your connection supports it, enter the emailed code in the same conversation. You do not need a desktop extension for that step. If the code box closes, send the code as a normal reply in that conversation. Continue with the same saved draft and wait for scheduling confirmation.

Already connected, but a tool is missing?

Official Narrareach plugin: new or changed tools become available after OpenAI approves them. Installing again or reconnecting does not bypass that review. Try a new chat with Narrareach selected once the update is available.

Custom connection: open its settings in ChatGPT in a browser. If Refresh is available, select it, check the tool list, then start a new conversation. Reconnect or Change connection may only repeat sign-in; they do not confirm that new tools were added.

If Refresh is missing or Substack verification is still unavailable, contact Narrareach support with the missing action and whether you use the official plugin or a custom connection. Keep your existing draft and publishing accounts connected. A managed workspace may need an administrator to review and enable new actions.

Contact Narrareach support
Optional: set up a custom connection

Use this route if you prefer a custom connection and your ChatGPT account allows it.

  1. Open ChatGPT Plugins in your browser. Click Add (or the plus button), then Add custom MCP server.
    ChatGPT Add menu with a yellow arrow pointing to Add custom MCP server, the last option.
    Choose Add custom MCP server to open the connection form.
  2. In the form that opens, use Narrareach as the name and the server address below. Choose OAuth for authentication; leave client ID and client secret empty.

    New Plugin

    ×

    Icon (optional)

    +

    An icon is optional.

    Connection

    Server URLTunnel
    https://www.narrareach.com/mcp

    Authentication

    OAuth▾

    Advanced OAuth settings

    Review discovered OAuth settings, or enter them manually.

    Custom MCP servers introduce risk. Learn more

    Create as a plugin
  3. Review the warning, choose I understand and want to continue, then Create as a plugin. Finish Narrareach sign-in and install the resulting plugin.
  4. Start a new chat, select Narrareach with @, and ask it to show your connected accounts.

https://www.narrareach.com/mcp

If these controls are unavailable, use the official listing above or ask your workspace administrator about access.

OpenAI’s current custom connection guide

Common questions

Why does ChatGPT say “Resource not found” when the Narrareach tools are visible?
ChatGPT may be unable to resolve a cached plugin action or an earlier attachment before it sends the request to Narrareach. Start a new chat so ChatGPT reloads the available actions. If an image was attached, attach it again. If the error continues, contact Narrareach support with the exact message. Keep the existing draft; a successful account check alone does not confirm that scheduling is available.
How should I send a ChatGPT-generated image with an article?
Send the actual image bytes, not a temporary ChatGPT attachment reference or ablob: or file: URL. Ask ChatGPT to use schedule_article with coverImage or media as a data URI or base64 value. It can also call upload_media first and use the returned public URL.
Can create_draft save an article image by itself?
create_draft accepts a title and optional HTML body; it does not accept an attached image object. To keep the article as a draft, create it first and then call update_draft with coverImage. To schedule immediately, use schedule_article, which accepts cover and inline media.
Gemini

Add Narrareach as a Gemini custom app

In Narrareach, open Settings > Integrations > Gemini, then add a custom app in Gemini with the values below. Leave Advanced features closed unless Gemini asks for credentials. Gemini should register the OAuth client automatically.
  1. On a computer, open gemini.google.com and go to Settings → Connected Apps.
  2. If Connected Apps is hidden, open Personal Intelligence first, then Connected Apps.
  3. Under Custom apps, choose Add a custom app. Paste the Connector URL below, then click Next.
  4. Complete Narrareach sign-in with the same email as your Narrareach account.
  5. In a chat, type @Narrareach to select the connector explicitly.
Connector URL
https://www.narrareach.com/mcp
Google account requirements
Google currently requires users to be 18 or older, located in the United States, using Gemini in English with a personal Google Account and Keep Activity on. Work or school accounts cannot connect custom apps. Connect the app in the Gemini web app first; after that it can also be used on mobile.
Admin note
Narrareach publishes Clerk's Dynamic Client Registration endpoint and PKCE S256 support through its OAuth metadata. Gemini should therefore register itself from the Connector URL; users do not need a client ID or secret. If Google changes its client onboarding method, verify the live authorization request before changing Clerk.
Notion

Use Narrareach in Notion Agents

This connects Narrareach's MCP tools to Notion Agent or an individual Notion Custom Agent. It is separate from the Notion page-import connection in Narrareach Settings. Notion requires a Business or Enterprise plan and web or desktop setup; custom MCP servers must be enabled by your workspace admin. No Narrareach API token or client secret is needed.
Connector URL
https://www.narrareach.com/mcp

Notion Agent

  1. On Notion web or desktop, open Settings → Connections → Discover → Add Custom MCP.
  2. Enter the Connector URL and sign in with your Narrareach account.
  3. Find Narrareach under All sources → MCP servers in chat. Mention it by name if the agent does not select it.

Custom Agent

  1. Open the agent's Settings → Tools & Access → Add connection → Custom MCP server.
  2. Enter the Connector URL, sign in with Narrareach, and choose the tools this agent can use.
  3. Keep write tools set to require confirmation, especially scheduling and publishing actions.
Access and troubleshooting
Notion Agent and every Custom Agent require separate connections. An admin must enable custom MCP servers and, in an approved-only workspace, approve this URL. A Custom Agent uses the Narrareach permissions of the person who connects it, including when teammates interact with that agent; limit agent access accordingly. If tools are missing, check the connection status and refresh the agent settings before reconnecting.
Make

Connect a Make scenario through the REST API

Use Make's HTTP module with a scoped Narrareach automation token. Keep the token in Make's credential storage, map only approved content into the request, and preserve the returned Narrareach identifier for status checks and safe retries.
  1. Create a token in Narrareach Settings > Integrations > REST API & webhooks with only the required scopes.
  2. Add an HTTP request module and use the endpoint and body from the public OpenAPI contract.
  3. Store the token as a credential and send it in the Authorization header.
  4. Use a stable source-record ID as the idempotency key. Notes accept the Idempotency-Key header or idempotencyKey in the body; articles take it in the body.
  5. Store the accepted item ID, then check status before retrying after a timeout.
n8n

Use the Narrareach community node in n8n

Install n8n-nodes-narrareach for native actions to schedule Articles and Notes, check status, reschedule, cancel, work with reader activity, and read Stats outcomes. n8n handles triggers and branching while Narrareach handles connected destinations and publishing state. To start a workflow when a Note publishes or fails, use n8n's Webhook node with a Narrareach webhook.
  1. Install n8n-nodes-narrareach under Community Nodes.
  2. Create a scoped Narrareach automation token and save it only in the n8n credential.
  3. Map approved content, destination, schedule time, timezone, and a stable source ID.
  4. Run one future-dated canary and confirm it with Get Status before enabling the workflow.
OAuth metadata

Discovery endpoints

LLM clients discover Narrareach auth from standards-based metadata. These endpoints must remain public and served over HTTPS.
MCP resource
https://www.narrareach.com/.well-known/oauth-protected-resource/mcp
Auth server (ChatGPT)
https://www.narrareach.com/.well-known/oauth-authorization-server/mcp
Auth server (Clerk)
https://clerk.narrareach.com/.well-known/oauth-authorization-server
Resource
https://www.narrareach.com/mcp
Required
The authorization metadata must include a registration_endpoint.
Required
PKCE support must advertise S256.
Publishing guide

Edit scheduled LinkedIn posts with ChatGPT

Use ChatGPT, Claude, or another connected MCP assistant to review and change a queued, text-only LinkedIn post in your personal Narrareach account. Publishing must not have started. This does not edit media posts, published posts, or scheduled articles.
  1. Ask your assistant to find the post with list_scheduled_items, check get_scheduled_item_readiness, and read the queued text with get_note.
  2. Provide the replacement text and ask for a preview. The assistant uses amend_scheduled_note_content with the schedule id, the current revision as expectedRevision, and your full replacement text. Previewing alone does not change the post.
  3. Review the preview and confirm before the assistant applies it with apply: true. If the post has changed, review a fresh preview before confirming again.
Example request: “Show me tomorrow’s LinkedIn post. Preview this replacement text, but don’t apply it until I confirm.” To move a Note or article to a different time, use amend_scheduled_item instead. Team Note changes still use the team dashboard.

Inspect article drafts and change covers

Article readiness includes a draftId. Use it with get_draft to review the Narrareach draft, not a verified copy of what is scheduled on the publishing platform. For an unscheduled article, update_draft can change its title, body, or cover image. Cover-only edits preserve the body and existing subscribe controls. It cannot edit an active article schedule. Review the schedule status before making changes; do not cancel or recreate it without approval.
Existing connections

Get new tools in your MCP connection

Official Narrareach plugin: new or changed tools become available after OpenAI approves them. Installing again or reconnecting does not bypass that review. Try a new chat with Narrareach selected once the update is available.
Custom connection: open its settings in ChatGPT in a browser. If Refresh is available, select it, check the tool list, then start a new conversation. Reconnect or Change connection may only repeat sign-in; they do not confirm that new tools were added.
If Refresh is missing or Substack verification is still unavailable, contact Narrareach support with the missing action and whether you use the official plugin or a custom connection. Keep your existing draft and publishing accounts connected. A managed workspace may need an administrator to review and enable new actions.
OpenAI’s connection and refresh guide
Tool catalog

What LLMs can do

Connected clients can work with drafts, notes, scheduling, inspiration, analytics, and profile context across Substack, Medium, LinkedIn, X, Bluesky, Threads, Instagram, Facebook, TikTok, and Pinterest. Tool access is scoped to the authenticated Narrareach user. Scheduling responses include the Narrareach item URL; published platform URLs are returned once the destination confirms publish. Article responses may also include non-blocking advisories; relay these as status updates without treating the accepted schedule as a failure.

Choose the account before acting

Call list_workspaces to see the teams and writers you can access. The tool details below show which calls accept workspace andwriter. Drafts, article scheduling, and schedule changes currently use your personal account. Keep the same workspace when listing, reading, and scheduling team Notes. If team access fails, do not switch to personal publishing to work around it.

Check Notes and articles separately

For Notes and social posts, use list_notes, thenget_note with the returned id. For articles, use list_scheduled_posts and find the scheduleid, not the draft id. After a timeout, an empty article list does not tell you whether a Note was scheduled. Check the right account, filters, and list limit before submitting again. Team Note changes currently use the team dashboard.
Tool
Description
list_workspaces
List the personal account and authorized team workspaces, writers, and publications.
Account and fields

Discovers context from your signed-in account. No selectors needed.

Required fields: None.

Accepted fields: None.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_user_profile
Read the current user profile, plan, timezone, connection status, and available publishing context.
Account and fields

Discovers context from your signed-in account. No selectors needed.

Required fields: None.

Accepted fields: None.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_drafts
Find drafts in your personal account by title or status.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: limit, status, query.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_draft
Read the complete content and metadata for one authorized draft.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id.

Use the schema supplied by your MCP client for field types, choices, and limits.

create_draft
Save an article draft in your personal account without scheduling it.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: title.

Accepted fields: title, contentHtml.

Use the schema supplied by your MCP client for field types, choices, and limits.

update_draft
Update the title, body, or cover image of an unscheduled article draft.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id, title, contentHtml, coverImage.

Use the schema supplied by your MCP client for field types, choices, and limits.

archive_draft
Archive an owned draft after active schedules have been handled.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_content_versions
List a saved Note and the article drafted from it, each with its own status and destinations.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: draftId.

Accepted fields: draftId, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

create_article_from_note
Create a linked article draft from a saved Note. The Note is kept, and nothing is published.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: draftId.

Accepted fields: draftId, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_notes
Find scheduled, published, or failed Notes and social posts.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: limit, status, platform, query, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_note
Read one authorized Note and its destination state.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: id.

Accepted fields: id, workspace.

Use the schema supplied by your MCP client for field types, choices, and limits.

schedule_note
Schedule short-form content to supported connected publishing destinations.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: scheduledFor, platforms.

Accepted fields: draftId, title, content, scheduledFor, timezone, platforms, socialAccountIds, instagramDestinations, linkedInAccountId, linkedInOrganizationUrn, workspace, writer, publication, confirmProfileDestination, substackConnectionId, imageUrls, videoUrls, threadsTopicTag, firstReply, platformVersions, media.

Conditional field: postingAs. Available only when your connected tool schema includes it. Select a connected Substack pen name, profile handle, or publication label. Use postingAs or publication, not both. This field does not grant access to another account.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_scheduled_posts
List article schedules in your personal account.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: limit, status, from, to.

Use the schema supplied by your MCP client for field types, choices, and limits.

cancel_scheduled_post
Cancel an article schedule from list_scheduled_posts.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id.

Use the schema supplied by your MCP client for field types, choices, and limits.

schedule_article
Schedule a full article to supported connected long-form destinations.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: platforms.

Accepted fields: draftId, title, contentHtml, subtitle, coverImage, media, tags, sendToNewsletter, isPaidContent, paywallMarker, addSearchMetadata, linkedinShareCommentary, linkedinPublicationType, linkedinAuthorUrn, linkedinNewsletterUrn, scheduledFor, platformSchedules, timezone, platforms, publication, substackConnectionId, mediumPublicationId, mediumNotifyFollowers.

Conditional field: mediumPublicationId. Only valid when platforms includes MEDIUM. Call list_medium_publications and pass its returned id; never guess one. When canPublish is false the story is submitted for editorial review and left unscheduled until an editor accepts it. A rejection by the publication is best-effort — the story still goes to the personal profile and the rejection is returned as a warning.

Conditional field: mediumNotifyFollowers. Only valid when platforms includes MEDIUM. Defaults to false (no subscriber email).

Use the schema supplied by your MCP client for field types, choices, and limits.

get_substack_verification_status
Check whether your Substack connection needs a code.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: connectionId.

Accepted fields: connectionId.

Use the schema supplied by your MCP client for field types, choices, and limits.

start_substack_verification
Request a Substack verification code in this conversation.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: connectionId.

Accepted fields: connectionId.

Use the schema supplied by your MCP client for field types, choices, and limits.

complete_substack_verification
Submit the Substack code provided by the user.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: connectionId, id, code.

Accepted fields: connectionId, id, code.

Use the schema supplied by your MCP client for field types, choices, and limits.

cancel_substack_verification
Cancel one Substack code request.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: connectionId, id.

Accepted fields: connectionId, id.

Use the schema supplied by your MCP client for field types, choices, and limits.

verify_substack
Request and enter a Substack code in your current conversation.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: action, connectionId.

Accepted fields: action, connectionId, id, code.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_linkedin_article_destinations
Refresh and list LinkedIn article profiles, Company Pages, and newsletters. Does not publish content.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: authorUrn, refresh.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_medium_publications
List the Medium publications the connected account can submit stories to. Does not publish content.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: refresh.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_linkedin_destinations
Refresh and list connected LinkedIn profiles and Company Pages for short-form posts. Does not publish content.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_social_accounts
List connected Threads, Facebook, TikTok, Pinterest and X accounts for short-form posts. Does not publish content.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_instagram_destinations
List connected Instagram accounts for short-form posts. Does not publish content.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_hashtag_sets
List your saved hashtag sets.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: None.

Use the schema supplied by your MCP client for field types, choices, and limits.

save_hashtag_sets
Save your hashtag sets: up to 20 sets of up to 30 hashtags each. Never inserts hashtags into content or publishes anything.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: sets.

Accepted fields: sets.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_scheduled_items
Review Notes and articles together with their destinations, times, and readiness checks.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: kind, status, from, to, limit, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_scheduled_item_readiness
Inspect one scheduled Note or article before making changes.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id, kind.

Use the schema supplied by your MCP client for field types, choices, and limits.

amend_scheduled_item
Preview and confirm a time change for a scheduled Note or article.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id, expectedRevision, scheduledFor.

Accepted fields: id, kind, expectedRevision, scheduledFor, timezone, apply.

Use the schema supplied by your MCP client for field types, choices, and limits.

update_scheduled_note_account
Send an already scheduled Threads, Facebook, TikTok, Pinterest or X post from a different connected account.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id, accountId.

Accepted fields: id, accountId.

Use the schema supplied by your MCP client for field types, choices, and limits.

amend_scheduled_note_content
Preview and edit the text of a queued, text-only LinkedIn post.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id, expectedRevision, content.

Accepted fields: id, expectedRevision, content, apply.

Use the schema supplied by your MCP client for field types, choices, and limits.

reschedule_scheduled_item
Move an authorized queued Note or article to a new time.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id, scheduledFor.

Accepted fields: id, kind, scheduledFor, timezone.

Use the schema supplied by your MCP client for field types, choices, and limits.

cancel_scheduled_item
Cancel an authorized queued Note or article without deleting its source draft.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: id.

Accepted fields: id, kind.

Use the schema supplied by your MCP client for field types, choices, and limits.

upload_media
Upload supported image or video bytes for later use in an authorized publishing workflow.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: kind.

Accepted fields: kind, sourceType, url, data, mimeType, fileName, file.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_inspiration_posts
Browse inspiration posts saved by the authenticated user.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: limit, platform, tag.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_benchmark_inspiration
Read saved writing experiments and optional inspiration for eligible pilot accounts.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: None.

Use the schema supplied by your MCP client for field types, choices, and limits.

prepare_benchmark_inspiration
Prepare low-confidence draft comparisons from saved examples for eligible pilot accounts.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: recordId, niche.

Accepted fields: recordId, niche.

Use the schema supplied by your MCP client for field types, choices, and limits.

list_reader_activities
List owned Substack likes, comments, and restacks.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: None.

Accepted fields: state, type, sort, cursor, limit, substackConnectionId.

Use the schema supplied by your MCP client for field types, choices, and limits.

reply_to_reader_activity
Publish a reply to an owned, replyable Substack comment.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: activityId, text.

Accepted fields: activityId, text, idempotencyKey, substackConnectionId.

Use the schema supplied by your MCP client for field types, choices, and limits.

update_reader_activity
Move an owned reader activity item between Inbox and History.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: activityId, triageState.

Accepted fields: activityId, triageState, substackConnectionId.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_platform_analytics
Fetch supported account and post analytics, or return stored metrics. May refresh connection and analytics data; does not publish content.
Account and fields

Personal account only. Do not send workspace or writer.

Required fields: platform.

Accepted fields: platform, recentLimit.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_stats_insights
Read stored Narrareach Stats insights for a selected period.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: period, from, to, platforms, contentTypes, publicationId, workspace.

Use the schema supplied by your MCP client for field types, choices, and limits.

get_voice_profile
Read the writer's voice profile: how they sound, their do and don't rules, topics, stances, real material, instructions, and a few of their own posts as examples.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

save_voice_preference
Save one writing preference the writer has just stated as a rule in their voice profile.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: kind, text.

Accepted fields: kind, text, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

add_voice_material
Save a real story, number, opinion, or example the writer has just shared to their material bank.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: type, text.

Accepted fields: type, text, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

decide_voice_suggestion
Record the writer's answer to one suggestion about how they write: approve, dismiss, or ask later.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: suggestionId, decision.

Accepted fields: suggestionId, decision, text, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

update_voice_rule
Reword one rule in the writer's voice profile.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: ruleId, text.

Accepted fields: ruleId, text, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

remove_voice_rule
Remove one rule from the writer's voice profile.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: ruleId.

Accepted fields: ruleId, workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

undo_voice_change
Undo the most recent change to the writer's voice profile.
Account and fields

Personal account by default; accepts an authorized team workspace.

Required fields: None.

Accepted fields: workspace, writer.

Use the schema supplied by your MCP client for field types, choices, and limits.

Open the complete agent-ready MCP tool reference
Media

Scheduling with images and video

schedule_note accepts imageUrls for public HTTPS images and media for pasted clipboard images, data URIs, or raw base64. Inline media is uploaded first, then the scheduled note stores the returned public URL. Article images and videos are handled through article HTML or draft media, not a top-level imageUrls field on schedule_article. Server-to-server callers can pass note images to POST /api/v1/noteswith imageUrls.
Platform
Note media limit
Substack
Up to 6 images
X
Up to 4 images or 1 video; images and video cannot be mixed
Bluesky
Up to 4 images or 1 video; images and video cannot be mixed
Instagram
At least one media item is required; up to 10 total media items
TikTok
Up to 35 images or 1 video; images and video cannot be mixed
Pinterest
One media item is required
LinkedIn
Images are supported through the connected posting path
Threads
Images are supported through the connected posting path
Facebook
Images are supported through the connected posting path
JSON-RPC example
{
  "jsonrpc": "2.0",
  "id": "schedule-image-note",
  "method": "tools/call",
  "params": {
    "name": "schedule_note",
    "arguments": {
      "content": "A short note with an attached image.",
      "platforms": ["SUBSTACK", "X", "THREADS"],
      "scheduledFor": "2026-07-01T14:00:00.000Z",
      "timezone": "America/New_York",
      "threadsTopicTag": "Creator Economy",
      "imageUrls": ["https://cdn.example.com/note-image.png"]
    }
  }
}
Local URLs
blob: and file: URLs cannot be fetched by Narrareach. Upload the media or pass it through media.
Validation
Platform media limits are checked before Narrareach creates scheduled rows.
REST API

Schedule articles from your server

REST callers can schedule full articles with POST /api/v1/articles. Article scheduling supports SUBSTACK, MEDIUM,LINKEDIN, and X. Use an automation token witharticles:write; note-only tokens cannot schedule articles. LinkedIn articles must be scheduled at least 20 minutes ahead. SetaddSearchMetadata to generate SEO metadata for supported article destinations; X does not expose separate article SEO settings.
scheduledFor accepts an RFC 3339 timestamp with eitherZ or an explicit UTC offset; Narrareach normalizes it to UTC.
LinkedIn Notes can publish from the connected personal profile or an administered Company Page. Call GET /api/v1/linkedin/destinations and send the returned accountId as linkedInAccountId. For a Page, also send linkedInOrganizationUrn. Omit both to use the Settings default or the only available personal profile. Narrareach never guesses among Company Pages. If several destinations exist and none can be selected safely, the request fails with LINKEDIN_DESTINATION_REQUIRED.
To choose which Threads, Facebook, TikTok, Pinterest or X account a Note goes to, call GET /api/v1/social-accounts and send the returned accountId keyed by platform in socialAccountIds. Without it, the Note posts to that platform's only account or its default. If several accounts are connected and none is the default, the request fails with SOCIAL_ACCOUNT_CHOICE_REQUIRED.
To choose an Instagram account, or to send one Note to several, call GET /api/v1/instagram/destinations and send the returned accountId values in instagramDestinations. Without it, the Note posts to the defaultDestination that call reports. If defaultIsAmbiguous is true, name the account.
LinkedIn Articles can publish from the signed-in personal profile or an administered Company Page. Call GET /api/v1/linkedin/article-destinations, choose a returned authorUrn, and send it aslinkedinAuthorUrn. Call the same endpoint withauthorUrn to list that profile or Page's newsletters. For a newsletter issue, also send linkedinPublicationType: "newsletter"and the returned linkedinNewsletterUrn.
A Medium article publishes to the connected account's own profile by default. To submit it to a publication instead, call GET /api/v1/medium/publications and send a returned id as mediumPublicationId. The publication list is saved for this connection; use ?refresh=1 when publication access changes to check Medium again. When canPublish is false for that publication, the story is submitted for editorial review and left unscheduled — it goes live when an editor accepts it, not at the requested time, and never publishes to the personal profile behind the publication's back. Submitting is otherwise best-effort: if the publication rejects the story, it still publishes or schedules to the personal profile and the rejection is returned in warnings, not as a failure. Set mediumNotifyFollowers: true to email Medium subscribers about the story; it defaults to false and is applied on the same best-effort basis.
Identify the Substack destination with publication as an exact connected publication name, handle, or URL. If omitted, Narrareach can select a sole active publication. Otherwise, the caller must ask the user which publication to use.
When LinkedIn has a pending connection sync, create and reschedule requests return HTTP 409 withPLATFORM_SESSION_REFRESH_REQUIRED andcanRetryAfterSync: true. New article input is saved first, and create responses include saved: true with the saved draftId. Nothing is scheduled until the connection is synced; sync LinkedIn in Platform connections, then retry the same request using that draft.
Uploaded article video is available for Substack-only article requests. Addkind: "video" to an item in mediaand place it with a 1-based {{media:N}} marker incontentHtml. Omitting kind remains backward-compatible and treats the item as an image. Narrareach accepts MP4, WebM, MOV, and M4V video up to 100MB when fetched from a public URL; inline REST data is additionally limited by the 15,000,000-character request field (about 10.7 MiB of decoded base64 bytes). A request containing article video is rejected with VIDEO_REQUIRES_SUBSTACK_ONLY if Medium, LinkedIn, or X is also selected, so uploaded video is never silently omitted. YouTube iframe input is normalized before saving: it publishes as a native inline embed on Substack and remains visible as a canonical link on selected destinations that cannot embed it. Vimeo iframe input is preserved as a canonical link on every selected destination. If saved structured content and HTML disagree about the number or identity of their videos, Narrareach returnsCONTENT_OUT_OF_SYNC before publishing; re-save the draft and retry. Video preparation may continue after a schedule is accepted. Check the schedule status instead of submitting another article. A VIDEO_PROCESSING response means the video is not ready yet. VIDEO_DISABLED with HTTP 503 means video publishing is temporarily unavailable; retry after service is restored.
Successful article create and reschedule responses may include anadvisories array when a selected platform is experiencing publishing delays. Advisories are informational: the request remains accepted, no acknowledgement is required, and actionRequired is false.
For retry-safe note creation, send a stable Idempotency-Key header toPOST /api/v1/notes. The existing idempotencyKeybody field remains supported and must match the header when both are present. New idempotent note responses include an operationId; useGET /api/v1/operations/:id with notes:read to inspect recovery status after a timeout.
Read the current delivery state with GET /api/v1/article-schedules/:idor GET /api/v1/notes/:id. Status responses are ownership-scoped and never cached. Integrations can validate a stored credential without scheduling content throughGET /api/v1/auth/check.
Reader activity is available through GET /api/v1/reader-activitieswith activity:read. UsePOST /api/v1/reader-activities/:id/replies to reply to an owned comment and PATCH /api/v1/reader-activities/:id to move an item between Inbox and History; both require activity:write. The matching MCP tools are list_reader_activities,reply_to_reader_activity, andupdate_reader_activity.
Threads notes may include one optional threadsTopicTag through eitherschedule_note or POST /api/v1/notes. IncludeTHREADS in platforms. The topic is limited to 50 characters and cannot contain periods, ampersands, or line breaks; it is stored only on the Threads destination when a note targets multiple platforms.
Notes may also include an optional firstReply throughschedule_note or POST /api/v1/notes. Narrareach applies each destination's own length rules—including X weighted characters—and reports where the reply was accepted or omitted. A reply that cannot be used never cancels the root note.
Note character limits are Bluesky 300, Threads 500, LinkedIn 3,000, and X 25,000 weighted characters (posted as a thread); Substack and the other destinations have none. With schedule_note or POST /api/v1/notes, pass platformVersions, such as { "BLUESKY": "..." }, to supply text that fits a platform. A version that is still over its limit is rejected before anything is scheduled. A platform without a version gets an automatic cut at a sentence break. Every platform that posts different text from the note is listed in adjustedPlatforms with the exact text, and an automatic cut also adds a warning to relay to the user.
Create
POST /api/v1/articles creates or schedules an existing draft.
Move
PATCH /api/v1/article-schedules/:id changes the queued time.
Read
GET /api/v1/article-schedules/:id returns the current state.
Cancel
DELETE /api/v1/article-schedules/:id cancels a queued article.
Schedule article
curl -X POST https://www.narrareach.com/api/v1/articles \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My full article",
    "subtitle": "Optional subtitle",
    "contentHtml": "<p>Free preview.</p>[[PAID_SECTION]]<p>Paid section.</p>",
    "platforms": ["SUBSTACK"],
    "publication": "@theainewsroom",
    "scheduledFor": "2026-12-01T14:00:00.000Z",
    "timezone": "America/New_York",
    "sendToNewsletter": true,
    "paywallMarker": "[[PAID_SECTION]]",
    "addSearchMetadata": true,
    "idempotencyKey": "article-2026-12-01-001"
  }'
List LinkedIn Article destinations
curl \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  "https://www.narrareach.com/api/v1/linkedin/article-destinations"

# Then list newsletters for one returned author:
curl \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  "https://www.narrareach.com/api/v1/linkedin/article-destinations?authorUrn=urn%3Ali%3Afsd_company%3A110374957"
List Medium publications
curl \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  "https://www.narrareach.com/api/v1/medium/publications"
Schedule Medium article to a publication
curl -X POST https://www.narrareach.com/api/v1/articles \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My Medium story",
    "contentHtml": "<p>Full article body.</p>",
    "platforms": ["MEDIUM"],
    "mediumPublicationId": "the_id_from_list_medium_publications",
    "mediumNotifyFollowers": false,
    "scheduledFor": "2026-12-01T14:00:00.000Z",
    "timezone": "America/New_York"
  }'
Schedule Substack article video
curl -X POST https://www.narrareach.com/api/v1/articles \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Article with video",
    "contentHtml": "<p>Watch the walkthrough:</p>{{media:1}}",
    "media": [{
      "kind": "video",
      "sourceType": "url",
      "url": "https://cdn.example.com/walkthrough.mp4",
      "mimeType": "video/mp4",
      "fileName": "walkthrough.mp4"
    }],
    "platforms": ["SUBSTACK"],
    "publication": "@theainewsroom",
    "scheduledFor": "2026-07-01T14:00:00.000Z",
    "timezone": "America/New_York"
  }'
Reschedule article
curl -X PATCH https://www.narrareach.com/api/v1/article-schedules/scheduled_post_id \
  -H "Authorization: Bearer $NARRAREACH_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduledFor": "2026-07-02T14:00:00.000Z",
    "timezone": "America/New_York"
  }'

Schedule Substack posts and articles with the Narrareach API

Use Narrareach’s article scheduling API to publish a newsletter article at a chosen time, set its free preview, and include a native subscribe button. The same publishing workflow is available through the Narrareach MCP connector in ChatGPT or Claude. These are Narrareach endpoints for your connected publications—not endpoints supplied by Substack.

This guide covers long-form articles. For short Substack Notes, use schedule_note or POST /api/v1/notes instead. A paid article’s access setting, its paywall position, and its email-delivery setting are separate decisions.

Before your first article request

  1. Connect the intended publication in Narrareach and confirm it is ready. API access does not connect an account automatically.
  2. For REST, use an account with API access and an automation token with articles:write. Send it as Authorization: Bearer <token>. Keep it on your server, never in client-side code or shared examples.
  3. For ChatGPT or Claude, use the authorized Narrareach connector. You do not need to paste an API token into the conversation.
  4. Choose the publication, a future publishing time and timezone, reader access, and whether to send email. Confirm these choices with the writer before scheduling.

Send publication as a connected publication name, handle or URL. Narrareach can select a sole active Substack publication when omitted; when there are multiple possibilities, choose explicitly. Sending it explicitly is the clearest option for repeatable automations. Check plan access and the OpenAPI reference for the current endpoint requirements.

Free preview, paid subscribers and newsletter email

Public article
Use isPaidContent: false without a paywall divider. Adding a subscribe button does not make an article paid.
Paid article with a free preview
Put <hr data-type="paywall"> after the free portion. Narrareach treats an explicit divider as paid access, even if isPaidContent was omitted or false. Select only Substack for this version.
Paid audience without a custom divider
Use isPaidContent: true. This selects paid access; it does not choose a custom preview boundary for you. Include a divider when you want a specific free excerpt.
Email delivery
sendToNewsletter defaults to true for a new article. Set it to false when you want to publish without sending the newsletter email. Adding a paywall does not change that choice.

A Substack paywall is not a portable access control for LinkedIn, Medium or X. Create a separate public excerpt or public article for those destinations. Do not send protected text to another platform assuming the Substack divider will protect it there.

Add a subscribe button with a caption

Place this HTML where the reader should see the subscription invitation. Use your own caption and escape quotation marks and other special characters in attribute values.

<div data-type="button" data-kind="subscribeCaption"
     data-text="Subscribe"
     data-caption="Get the complete guide and future editions."></div>

For a button without a caption, use data-kind="subscribe" and omit data-caption. An ordinary link remains a link; a shortened subscription URL does not automatically become a native subscribe button. A button and a paywall serve different purposes: one invites a subscription, the other sets where paid content begins.

Example: schedule a paid Substack post without sending email

Send this JSON to POST https://www.narrareach.com/api/v1/articles with your authorization header and Content-Type: application/json. Replace the example publication and date. The timestamp’s Z means UTC: 14:00 UTC is 09:00 in New York on this example date. An explicit UTC offset is also accepted; keep it consistent with your named timezone.

{
  "title": "A practical guide for newsletter writers",
  "contentHtml": "<p>This introduction is the free preview.</p><div data-type=\"button\" data-kind=\"subscribeCaption\" data-text=\"Subscribe\" data-caption=\"Get the complete guide and future editions.\"></div><hr data-type=\"paywall\"><p>This section is for paid subscribers.</p>",
  "platforms": [
    "SUBSTACK"
  ],
  "publication": "@your-publication",
  "scheduledFor": "2026-12-01T14:00:00Z",
  "timezone": "America/New_York",
  "isPaidContent": true,
  "sendToNewsletter": false,
  "idempotencyKey": "newsletter-guide-december-01"
}

If your content system uses a custom placeholder, put it once in the article text at the intended boundary and supply the same string as paywallMarker. For example, [[PAID_SECTION]] in contentHtml with paywallMarker: "[[PAID_SECTION]]". Do not place it in a URL or button caption. Native divider HTML is the most direct option.

Read the scheduling response

A newly accepted request returns HTTP 202. The following is an illustrative response; your IDs, status and dates will differ. Save both draftId and every scheduled[].id. A schedule ID identifies a scheduled delivery, not the article draft.

{
  "success": true,
  "mode": "schedule",
  "draftId": "draft_example",
  "article": {
    "id": "draft_example",
    "title": "A practical guide for newsletter writers",
    "status": "SCHEDULED"
  },
  "scheduled": [
    {
      "id": "schedule_example",
      "platforms": [
        "SUBSTACK"
      ],
      "status": "PENDING",
      "scheduledFor": "2026-12-01T14:00:00.000Z",
      "timezone": "America/New_York",
      "publishedAt": null,
      "error": null
    }
  ],
  "idempotencyKey": "newsletter-guide-december-01"
}

Acceptance is not proof of publication. The article summary says SCHEDULED, while a newly queued delivery starts as PENDING. Read GET /api/v1/article-schedules/:id using the returned schedule ID to check delivery state. These article-schedule endpoints use articles:write. Display informational warnings or advisories when present, but do not treat an advisory alone as failure.

Schedule an existing draft, reschedule or cancel

To schedule a saved article, send draftId instead of new title and body fields. This schedules its saved content and audience settings; it is not an edit operation. Review or update the draft first if those settings should change. Do not supply paywallMarker with an existing draft.

{
  "draftId": "draft_example",
  "platforms": [
    "SUBSTACK"
  ],
  "publication": "@your-publication",
  "scheduledFor": "2026-12-02T14:00:00Z",
  "timezone": "America/New_York",
  "idempotencyKey": "existing-draft-december-02"
}

To move an existing schedule, use PATCH /api/v1/article-schedules/:id with scheduledFor and, optionally, timezone. Do not create another schedule just to change the time. To cancel a queued delivery, use DELETE /api/v1/article-schedules/:id. Cancellation is not a way to retract an already-published article; read the current state before taking action.

Schedule a Substack newsletter from ChatGPT or Claude

With the Narrareach connector enabled, describe the result you want in ordinary language. You do not need to write HTML. For example:

Schedule my approved article to @your-publication on December 1 at 9 a.m. New York time. Keep the introduction free and put the paywall before “The complete guide.” Add a subscribe button just before the paywall with the caption “Get the complete guide and future editions.” Publish it without sending an email. Confirm the publication and these choices before scheduling.

The corresponding tool is schedule_article. It uses the same title, HTML content, destination, scheduling and audience fields; the REST idempotencyKey field and REST response envelope are not MCP tool arguments. If the intended boundary is unclear, the assistant should ask which paragraph ends the free preview. Clear placement should not require another formatting question. After scheduling, keep the returned result and use list_scheduled_posts, reschedule_scheduled_item or cancel_scheduled_item to manage it.

Handle errors and retries without duplicate articles

For REST article creation, send a stable idempotencyKey in the JSON body. After a timeout, check the queue and retry the same body with the same key rather than immediately creating a new request. A successful replay may return HTTP 200. If you intentionally change the request, first check whether the earlier schedule exists; then use a new key for the new operation. This article contract is separate from the Notes idempotency header.

For non-success responses, read error.code, error.message, error.resolution and any error.details. Keep useful recovery instructions visible to the writer.

400 · INVALID_PAYWALL_MARKER
Confirm one free-preview boundary. Remove conflicting positions or choose a separate public version for another platform; do not retry unchanged content.
400 · SUBSTACK_PUBLICATION_REQUIRED / SUBSTACK_PUBLICATION_AMBIGUOUS
Supply the exact connected publication name, handle or URL. Do not choose a publication on the writer’s behalf.
400 · VALIDATION_ERROR / INVALID_MEDIA
Check the fields identified by the response, your future publishing time, and the media requirements in the reference.
409 · PLATFORM_NOT_READY / PLATFORM_SESSION_REFRESH_REQUIRED
Reconnect the named platform in Narrareach. If the response includes a saved draftId, keep it and schedule that draft after reconnecting.
409 · CONTENT_OUT_OF_SYNC
Open and save the article in its editor, check the preview, then try scheduling again.
409 · IDEMPOTENCY_IN_PROGRESS
Wait and check the queue. Do not switch keys just to bypass an in-progress request.
409 · IDEMPOTENCY_CONFLICT
That key belongs to different request content. Check the earlier result before submitting an intentionally different request with a new key.

Authentication and access errors require a valid token, the required scope and an eligible account. For rate limits or temporary service errors, follow the returned retry guidance; do not continuously resubmit. Never send tokens, unpublished article bodies or account credentials in a support screenshot.

Next: review the REST endpoint examples, connect ChatGPT, or consult the complete request schemas.

Webhooks

Get notified when a Note publishes or fails

Narrareach can POST a signed JSON event to your HTTPS endpoint, such as a Make custom webhook or an n8n Webhook node, when a scheduled Note publishes or fails. Webhooks are included in Full Agentic Mode.
  1. Open Settings > Integrations > REST API & webhooks, paste your endpoint URL under Webhooks, and choose Add webhook.
  2. Copy the signing secret. It is shown once.
  3. Choose Test to send a webhook.test event and confirm the endpoint receives it. The test body carries only a message, not a Note.
  4. Branch on event: note.published or note.failed. The Note is in data.note.
Verify the signature
X-Narrareach-Signature is t=TIMESTAMP,v1=SIGNATURE. Compute an HMAC-SHA256 hex digest of TIMESTAMP.RAW_BODY with your signing secret and compare it with v1.
Retries and duplicates
Respond with a 2xx status within 8 seconds. Failed deliveries are retried, up to 5 attempts in total, so ignore events whose id you have already handled.
Scheduled Notes send events for Substack, LinkedIn, X, Threads, Instagram, Facebook, TikTok, and Pinterest. Notes posted right away through the REST API send events for every platform. Articles do not send webhook events yet, and scheduled Bluesky Notes may not send them, so check their status through the REST API.
See the payload and headers
Access

Plan and rate limits

Paid plans include MCP access, image-capable scheduling, and analytics. Full Agentic Mode includes REST API and webhook workflows for direct server-to-server integrations.
MCP limit
Each user gets 120 MCP request units per 10 minutes. A JSON-RPC batch consumes one unit per item in the batch.
Bulk scheduling
This allows a 62-item bulk Notes run plus setup and status calls. For image-heavy batches, keep normal client retry/backoff behavior enabled.
Troubleshooting

Common connection issues

Redirect URI mismatch
Confirm dynamic client registration is enabled. Dynamically registered clients provide their callback during registration. For a manually pre-registered client, add only the exact callback URI supplied by that client at the provider level.
Missing openid scope
ChatGPT requests openid during authorize. If the Clerk OAuth application only allows profile/email, add openid (and usually offline_access) on that OAuth client.
OAuth verification fails
If server logs mention an invalid JWT form, the endpoint is trying to parse an opaque Clerk OAuth credential as a JWT. Validate it through Clerk's OAuth-aware flow instead.
Localhost does not work in hosted clients
Claude, ChatGPT, and Gemini require HTTPS for remote connectors. Use the production URL or expose local development through an HTTPS tunnel.

Narrareach LLM connector

Connect Claude, ChatGPT, Gemini, or any MCP-compatible agent to read drafts, schedule posts, and automate Substack, Medium, LinkedIn, X, Bluesky, and Threads workflows.

Read the docs