Set up your blog
Import an existing blog or start from scratch, then get content areas, a topic map and a queue of headlines.
Generated from the app (prompt-collection), so always current.
This is the main event: the blog itself. Letterstory reads your site, imports whatever is already published, works out what you write about, and builds a map of what to write next.
The prompt
You are setting up (or tuning) a Letterstory main blog collection: how it decides what to write about, and how it publishes on its own. This assumes org context - manifesto, positioning, identity, ranking targets, competitors - is already reasonably set; get_onboarding_plan tells you whether it is (its context step is done when positioning exists; if not, do https://app.letterstory.com/docs/onboard/context first). This is also NOT about connecting your CMS/front end or setting up publish webhooks - that's https://app.letterstory.com/docs/onboard/cms; don't duplicate that work here.
Connect first:
- This guide is for an EXISTING Letterstory customer. If the user has somehow not signed up yet, that happens at https://app.letterstory.com/crossing/letter with a work email and is theirs to do in a browser, not something you can do over the API.
- Ask the user for their Letterstory API key if you don't have one (Letterstory dashboard -> Settings -> API keys -> Create key), sent as an x-integrations-key header (not Authorization: Bearer). In the Create key dialog, pick the "Onboarding + publishing agent" preset - a key created with the defaults can only read published posts, and almost every call below would fail on a missing capability. Keys are not issued over the API, so that step also happens in the browser.
- Get the tool schemas by POSTing a JSON-RPC tools/list request to https://app.letterstory.com/api/mcp - plain HTTP is fine, you do not need an MCP client. That is the ONLY place per-tool parameters live. https://app.letterstory.com/api/openapi describes the REST dispatcher (one generic tools/{name} path with an untyped body) and carries no per-tool schema, so it cannot tell you what a tool takes. Tool names below are anchors, not full signatures - look up the current schema before calling anything.
- Call get_onboarding_plan first. Its collection step is Phase 1 and its planner step is Phase 3: ready means run it, running means a job is already in flight (poll it, don't start another), done means this is a TUNING session - skip to "Already have a collection?" below instead of creating a new one. The planner step stays blocked until the collection has content areas; that is the blank-site case described in Phase 1, not a Planner problem. args_hint carries the main collection's id.
- Call list_collections to see what exists by name. Entries with hosted: true are PHANTOMS - independent publications Letterstory runs for the customer on other domains. A phantom is never the main blog: do not onboard into one, tune one here, or treat its posts as the customer's own. An org whose only collections are phantoms has NO main blog yet, and the plan's collection step says so.
Phase 1 - Create or onboard the collection
- ASK THE USER for direction before you call anything, and for collection_name if you are creating one. direction is not a throwaway label: it becomes the Planner's standing steering prompt, shaping the topic map and every headline generated from now on. Do NOT infer it from your own knowledge of the company, and do not quietly draft one from their positioning and pass it as though they said it - an agent's guess about what a company is for becomes that company's editorial policy. If the user cannot be reached, either omit direction entirely (the engine derives strategy from the site and positioning itself) or draft one and get it confirmed before calling.
- IF THE BLOG LIVES IN A CMS, CONNECT IT FIRST. Passing cms_provider when the import cannot run does not fail: it treats the gap as a setup gap, quietly builds the map from positioning instead, and leaves a "CMS import skipped" line in the review notes. The job still reports done and the customer's existing posts are simply never imported. Two different gaps trigger that, so checking list_cms_connections alone is not enough: the provider can be connected and the import still skip because there is no field mapping. For webflow, sanity and contentful the mapping is auto-detected from the live connection on first import, so a connection is sufficient. FRAMER HAS NO SCHEMA DETECTOR - it needs a mapping that already exists, so for framer check list_cms_mappings too and treat an empty list as not ready. GITHUB is the same: the customer's content repo is the source, and its mapping is a publish target (set_github_publish_target names the repo, branch and the path posts live at, e.g. content/posts/{slug}.md) - with no target, list_cms_mappings for github is empty and the import skips. Either way, if the provider is not connected (or is framer with no mapping), do https://app.letterstory.com/docs/onboard/cms before this step rather than after it.
- The normal path is onboard_collection (collection_name, direction, optionally sitemap_url / cms_provider - cms_provider accepts webflow, framer, sanity, contentful or github). It reads the org's stored domain, imports the existing blog (sitemap or connected CMS) or starts from positioning if there's nothing to import, derives content areas + series from what was actually written, builds the topic map, infers the org's table/Venn/generative-diagram styles from its own site and binds them on the collection, turns the guaranteed passes on (internal links off the blog's own sitemap, external sources, comparison tables — drawn only where a post's template commissions one, not every post — and free-form diagrams — but diagrams only turn on when a real style could be inferred from the site; otherwise they stay off rather than drawing in a generic house look), binds SEO demand, runs one GEO probe cycle, and stocks Headlines. It returns a job_id immediately - poll get_collection_onboard_status until done or failed. It's idempotent: re-running it later (e.g. after a rebrand changes positioning) fills gaps rather than resetting existing strategy, so it's also the safe way to refresh a stale map, not just the initial-setup tool.
- By default the Planner it configures is left OFF (manual approval) - nothing publishes unattended from a single unreviewed call. If you (the agent) already have the user's explicit go-ahead on cadence and approval posture - the same review the self-serve UI's Guided step walks a human through - pass enable_planner: true with cadence_per_week and approval_mode in the SAME onboard_collection call instead of a follow-up configure_collection. This also force-fills the queue with real picks from the headlines it just generated (matching "Fill queue"), not just empty scheduled slots waiting for someone to choose - under manual approval, an unfilled queue is the default and is NOT a bug, it just means nobody asked for enable_planner. Needs an acting user (a user-scoped key) same as configure_collection - a raw org-scoped key gets a clear error if you pass enable_planner without one.
- Only use bare create_collection (no onboarding) for a second/side collection you intend to build up manually with the tools below - it does none of the automatic derivation onboard_collection does.
- Verify: get_collection_onboard_status reports done, and list_topics on the resulting collection_id shows real pillars/spokes, not an empty map.
- Search Console: SEO demand is bound either way, but real clicks, impressions and queries for the blog's posts need Google Search Console connected. That is a Google sign-in a HUMAN does in a browser - you cannot do it over the API. Call get_gsc_connection: if connected is false (or site_selected is false), hand the user its connect_url and tell them to connect with the Google account that owns the site's Search Console property and pick the site. The plan's search_console step is optional for that reason; it never blocks the rest.
Phase 2 - Understand where headlines actually come from
- One pipeline feeds the queue - there is no sourcing mode to pick or tune. The topic map is pillars (clusters), each with spokes (candidate subtopics) - list_topics shows them with status open/queued/covered/dismissed; only 'open' is writable, and set_topic queues one onto the next slot. It's kept stocked automatically in the background; when a pillar's ground is fully worked out, the Planner proposes adding new, distinct pillars and generating their topics - a strategy proposal the user can approve, decline, or let apply itself automatically after 2 days - instead of just sitting dry. Series are a separate, named coverage obligation - one post per declared item - listed/created/backfilled with list_series / create_series / backfill_series (omit collection_id on create_series for an org-level series that runs on the main blog; backfill_series retroactively matches existing posts to declared items instead of duplicating them, which matters on a blog that isn't starting from empty).
- Each Planner tick gives a due series item first crack at the slot (a paced "continuity floor," e.g. not before ~14 days since that series last shipped), and a second chance as a fallback if the topic map and Curate both come up empty. If the topic map, Curate, AND the series fallback all come up empty, the Planner generates a headline straight from the steering prompt as a last resort - nothing waits on a human by default.
- The one remaining gotcha: if the topic map's open-spoke count hits zero at the exact moment a scheduled run with no topic already assigned needs one, the Planner parks that run waiting briefly BEFORE it ever tries to source anything - including the series lane. This self-heals on the next tick via the always-on background extend, but if headlines seem to be skipping a series, check list_topics for a momentarily empty open-spoke count before assuming the series itself is broken.
Phase 3 - Delivery and the Planner
- configure_collection turns the Planner on (or reconfigures it) in one call: cadence_per_week, approval_mode, and an optional steering_prompt. Approval defaults to 'manual' for a client collection - drafts wait for a human; only pass 'autopilot' if the user explicitly wants nothing reviewed before it publishes to a live brand. This call also materializes the upcoming publish slots.
- get_collection_config is the read counterpart - use it before changing anything on a collection that might already be configured, so you're editing from the real current state (the collection's one file: identity, content, cadence, publishing, targets, measurement) instead of guessing or silently overwriting a deliberate choice.
- This prompt does not cover wiring the actual destination (CMS connector, webhook, custom front end reading published content) - that's https://app.letterstory.com/docs/onboard/cms. Follow that guide for the delivery mechanics; this one is about what gets written and when.
- Verify: get_cadence_progress on this collection (or get_cadence_summary for every collection in the org) shows real published pace catching up to the target - not just that the call succeeded.
Already have a collection? (tuning, not first-time setup)
- Start with get_collection_config to see the real current state, then list_topics and list_series to see what's actually queueable right now.
- Adding a series to an established blog: create_series, then backfill_series so posts that already cover a declared item are matched as 'backfilled' instead of the Planner writing a duplicate.
- If headlines don't reflect a change you just made (a new series, a repositioned priority topic), check list_topics for an empty open-spoke count first - re-read Phase 2's gotcha before assuming the series is broken.
- There is no self-serve tool today to wholesale regenerate or re-pivot the topic map's pillars (a full strategic pivot, not adding coverage) - the available tools let you queue/dismiss individual spokes and layer on series. If a full pivot is what's needed, that's outside this API surface for now; re-running onboard_collection helps with drift/staleness but won't force a pivot away from an existing pillar set.
Guardrails:
- Never enable 'autopilot' approval without the user explicitly confirming they're comfortable with nothing reviewed before publishing to their live brand.
- This flow is for a customer's own account. It is not the staff-run "phantom"/hosted-storefront tooling (plan_phantom, set_phantom_config, onboard_domain, create_phantom, etc.) - don't reach for those here.
- If something in this flow doesn't match what tools/list or /api/openapi actually shows, trust the live schema over this prompt and tell the user what changed.
What to expect
It takes ten to twenty minutes on a real site, and it can look frozen for several minutes at a time while it is still working. That is normal. Importing a large blog is capped at 200 posts per run, so if you have more, run it again and it picks up where it left off.
Imported posts arrive as drafts. They are not republished anywhere until you say so.
The Planner stays off
When this finishes you have content areas, a topic map and suggested headlines, but nothing publishes on its own. The Planner is configured and switched off deliberately: a single unreviewed run should never start publishing to a live brand. Turn it on when you have looked at the map and chosen a cadence.
What done looks like
Your content areas reflect what you actually write about, the topic map has real subjects in it rather than an empty shell, and Headlines has suggestions waiting.