Schedule article
schedule_articleSchedule an article to Substack, Medium, LinkedIn Articles, X, WordPress, or Ghost. WordPress and Ghost support publishMode draft, which saves a remote draft without publishing or emailing. Always pass draftId for an article that is already saved (from create_draft, get_draft or list_drafts). title and contentHtml create a new draft and are only for an article that has not been saved yet. A new draft whose title matches an article still queued on the same platform is refused; to change a queued article, use amend_scheduled_item. Supports cover and inline images, Substack-only inline video, and destination-specific SEO metadata. Substack supports native paywall and subscribe controls at explicit positions in contentHtml; ordinary links remain links. Audience and email delivery are controlled by the supplied fields. LinkedIn Articles requires a separate browser-session connection from regular posts; pending session sync saves new input as a draft without scheduling. Settle content, title, paywall, audience and email delivery with the writer before calling. To change only the time of an article that is already scheduled, use amend_scheduled_item or reschedule_scheduled_item rather than cancel_scheduled_item followed by schedule_article. To publish right away, pass publishNow: true instead of inventing a time a few minutes ahead. Each returned post has writerState: tell the writer the article is published only when writerState is published, and share its liveUrl; scheduled or publishing means it is not live yet. Returns scheduling outcomes and advisories; an advisory with action RESYNC_LINKEDIN_ARTICLES means the LinkedIn article is scheduled but may not publish until the writer signs in to LinkedIn or resyncs LinkedIn Articles in Narrareach, so tell the writer its message. When reviewing a Substack article with the writer, briefly mention once per article that they can ask for a Subscribe button after a named paragraph, a caption beneath it, a paywall before a named section (a paywall makes the article paid-only), or a Freewall before a named section (everyone reads the opening; free and paid subscribers keep reading, and readers without an email are invited to subscribe free). Use the requested position; ask where only if it is ambiguous.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"platforms": "<platforms>"
},
"name": "schedule_article"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Optional tag list for newly created drafts. Substack receives all supplied tags. Medium receives its supported first 5 topics and returns a warning when extras are omitted. The saved draft remains unchanged. | |
| media | No | Optional inline images or Substack article videos for a newly created draft. Replaces {{media:N}} placeholders in array order; leftovers are appended. kind defaults to image; video requires Substack as the sole platform. Supports public URLs, data URIs, and base64 bytes. In ChatGPT, for a file the user attached in the chat, first call upload_media with it in file, then pass the returned publicUrl here as url. | |
| title | No | Required when creating a new draft. | |
| draftId | No | The saved article draft id to schedule. Pass it whenever the article was saved with create_draft or exists already. Its body is used as saved; isPaidContent and sendToNewsletter, when supplied, set its Substack audience and email delivery and must match its wall (a Freewall is never paid-only; a paywall is always paid). | |
| freewall | No | Make the article's single wall divider (or paywallMarker) a Substack Freewall: everyone sees the content above it; free and paid subscribers keep reading below it. Requires SUBSTACK and a publication with Substack Freewalls. For a new draft (title and contentHtml) it sets the Freewall. A saved draft (draftId) keeps the wall already in its body: a Freewall there is scheduled as a Freewall with or without this field, and true only confirms it. Never combine with isPaidContent. Default false. | |
| subtitle | No | Optional article subtitle for newly created drafts. Substack omits subtitles over 250 characters and returns a warning without changing the saved draft. | |
| timezone | No | IANA timezone the scheduledFor time(s) above are expressed in (e.g. "Europe/London"). Defaults to the writer's saved timezone, else UTC. | |
| coverFile | No | The approved cover image the user attached in ChatGPT, passed by the client, for a newly created draft. Use this OR coverImage, never both. For a saved draft (draftId), attach the cover first with update_draft coverFile. Never substitute another image. | |
| platforms | Yes | ||
| coverImage | No | Optional cover image for a newly created draft, placed at the top of the published body. Supports public HTTPS URLs, data URIs, or base64 image bytes. URL ingestion depends on source-host access. For an image attached in ChatGPT, use coverFile instead. For a saved draft (draftId), attach the cover first with update_draft. | |
| publishNow | No | Publish as soon as possible instead of at a set time. Use this, not a near-future scheduledFor, when the writer asks to publish now. Do not combine it with scheduledFor or platformSchedules. LinkedIn articles still need their minimum notice and go out at the earliest safe time. | |
| contentHtml | No | Required when creating a new draft. Supports public <img> or <video> elements and {{media:N}} placeholders resolved from media entries. Video articles require Substack as the sole platform. Native Substack paywall markup is <hr data-type="paywall"> at the selected paragraph boundary, or a single {{NARRAREACH_PAYWALL}} token; paywallMarker supports custom tokens. A Substack Freewall (free and paid subscribers keep reading) is <hr data-type="paywall" data-access="subscribers">, or set freewall to true. Native subscribe block markup is <div data-type="button" data-kind="subscribeCaption" data-text="Subscribe" data-caption="Your caption"></div> with HTML-escaped attribute values. data-kind="subscribe" represents a button without caption. Ordinary links remain links. Audience sections use a div with data-dynamic-content="true" and data-dynamic-audiences="paid_sub", containing data-dynamic-content-match="true" and data-dynamic-content-else="true" divs. Supported audience conditions: non_sub, free_sub, paid_sub, founding_sub (comma-separated). Keep both branches. Subscriber-tag targeting must be published in Substack. | |
| publication | No | Substack destination as a publication name, handle, or URL, for example "AI Newsroom", "@theainewsroom", or "https://theainewsroom.substack.com". Optional when exactly one active Substack publication is connected; Narrareach selects it automatically. Required when more than one active Substack publication is connected, except that when it is missing Narrareach uses the publication the writer scheduled or published to most recently and says so in substackPublicationSelection.message, with publicationChoices listing the others; tell the writer which one was used. If there is no previous choice, the value is ambiguous, or Narrareach cannot confirm the session publishes there, nothing is scheduled and the result has requiresPublicationChoice: true with publicationChoices (name, handle, url, substackConnectionId). Ask which one they want, then call again with publication set to the chosen handle (and draftId when a draft was already saved). | |
| publishMode | No | Only valid when all selected destinations are WordPress or Ghost. Defaults to publish; draft saves a remote draft at the scheduled time without publication. | |
| scheduledFor | No | Required unless publishNow or platformSchedules is given, and must be in the future. Shared local wall-clock publishing date/time interpreted in timezone, including DST. A Z or explicit UTC offset represents an absolute instant. LinkedIn articles require at least 20 minutes of lead time. | |
| isPaidContent | No | Whether the Substack article is paid-only. Default false. Do not combine with freewall. | |
| paywallMarker | No | Optional custom marker in contentHtml where the selected free preview ends; must appear exactly once. The standard {{NARRAREACH_PAYWALL}} marker is recognized without this field. Creates a native divider without changing sendToNewsletter. With freewall true it allows free and paid subscribers; otherwise it enables paid access. | |
| sendToNewsletter | No | Substack email delivery setting. Default true. | |
| addSearchMetadata | No | Generate SEO titles, descriptions, and a Substack slug for supported article destinations. SEO metadata is generated automatically on Revenue Writer, Full Agentic Mode, and Teams & Agencies, and for trials or other accounts with article SEO access. Set this option to false to turn it off. X does not support separate article SEO settings. | |
| linkedinAuthorUrn | No | LinkedIn personal profile or Company Page author URN belonging to the connected LinkedIn Articles account. | |
| platformSchedules | No | Optional per-platform overrides taking precedence over scheduledFor. Same wall-clock + timezone rule applies to each scheduledFor here; LinkedIn entries require at least 20 minutes of lead time. | |
| allowDuplicateTitle | No | Only after the writer confirms they want a second copy of an article with this title that is already queued on the same platform. Defaults to false. | |
| mediumPublicationId | No | Optional authorized Medium publication id when platforms includes MEDIUM. Absent means the personal profile. Writer-only access submits for editorial review and leaves the story unscheduled until acceptance. Explicit publication rejection allows personal-profile delivery with a warning; ambiguous submissions remain unpublished for review. Draft-only delivery does not submit to a publication. | |
| substackConnectionId | No | Exact Substack connection identifier, retained for backward compatibility, for example publicationChoices[].substackConnectionId from a requiresPublicationChoice result. publication is the preferred public destination selector; when both are given they must name the same publication. | |
| linkedinNewsletterUrn | No | LinkedIn newsletter URN belonging to the connected LinkedIn Articles account. Required when linkedinPublicationType is newsletter. | |
| mediumNotifyFollowers | No | Whether to email Medium subscribers about this story. true is only valid when platforms includes MEDIUM; false is ignored. Defaults to false (no email). Best-effort: a failure to apply this setting never blocks the publish/schedule and is reported as a warning. | |
| linkedinPublicationType | No | LinkedIn destination type. Defaults to an individual article; newsletter represents a user-selected newsletter destination. | |
| linkedinShareCommentary | No | Optional LinkedIn share text used when publishing a LinkedIn article. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | ||
| count | Yes | ||
| posts | Yes | ||
| message | No | ||
| nextStep | No | ||
| warnings | Yes | ||
| amendHint | No | ||
| advisories | No | ||
| choiceScope | No | ||
| aiVisibility | No | ||
| createdDraft | Yes | ||
| connectedAccount | No | ||
| publicationChoices | No | ||
| substackPublication | Yes | ||
| archivedEarlierCopies | No | ||
| publicationChoiceReason | No | ||
| archivedEarlierCopiesNote | No | ||
| requiresPublicationChoice | No | ||
| substackPublicationSelection | No |