Render your posts as static pages on your own site
A copy-paste prompt for your AI coding tool. Fetch published articles at build time and render real, indexable HTML, no CORS, no client-side fetch.
If your site is a Next.js, Astro, Vite, Jekyll, or Hugo app and you want your Letterstory posts to live on it as real pages (not an embed), the fastest path is handing your AI coding tool a prompt that does the whole job: fetch at build time, write static HTML, done.
GET /api/integrations/published has no CORS headers on purpose. Fetching it from the browser would serve crawlers an empty shell where your article should be, which defeats the point of publishing at all. Fetch it while the site builds instead, the same way these frameworks already pull from any other build-time content source.
Paste this into your AI coding tool
Fill in the three placeholders, then hand this to Claude Code, Cursor, or whatever you use to write code.
Pull published articles from Letterstory (a headless CMS) at build time and
render them as static, indexable HTML on this site.
Do NOT fetch this API from the browser: there are no CORS headers, and a
client-side fetch would serve crawlers an empty shell and hurt SEO/AEO.
Fetch during the build, write the pages as static HTML, and rebuild
whenever content changes (a rebuild on every push is fine to start; a
publish-triggered webhook is a fast follow-up, not required for launch).
## 1. Fetch the articles
GET https://app.letterstory.com/api/integrations/published?collection_id={{COLLECTION_ID}}
Header: x-integrations-key: {{API_KEY}}
- `collection_id` is optional: it scopes the list to one collection. Leave
it off to fetch everything this key can read.
- Optional: `format=md` for Markdown instead of HTML; `slug=` or
`article_id=` to fetch one article instead of the list.
- Response: `{ items: [...], count, next_cursor, has_more }`, newest-first,
up to `limit` (default and max 1000). If `has_more` is true, page with
`cursor=<next_cursor>` so a larger set of posts doesn't get silently
truncated.
- The key is server-side only (build script, CI secret): never ship it to
the browser, and never give it a client-exposed env var prefix (no
`NEXT_PUBLIC_`, `VITE_`, `PUBLIC_`, etc.).
- If the API call fails during a build, fail the build. Don't publish an
empty or partial page set over the last good deploy.
## 2. Each item's shape
{
"article_id": "...", "slug": "...", "collection_id": "...",
"title": "...", "content": "<html, or markdown when format=md>",
"summary": "...", // dek/excerpt
"cover_image": "...", "cover_image_alt": "...",
"author": "...", "author_profile": { "name", "slug", "bio", "role", "expertise", "started_at" },
"tags": ["..."],
"published_at": "...", "updated_at": "...",
"metadata": { "meta_tags": [ { "property": "...", "content": "..." } ], "json_ld": {...} },
"paper_trail": { "sources": [...], "citation": [...] } // cited sources, for provenance if you want to show it
}
Any field can be null except `article_id`, `slug`, and `format`.
## 3. Render
- One index page listing items (title, summary, cover, date) plus one page
per `slug` rendering `content`.
- Set <title>, meta description, canonical URL, Open Graph tags, and
JSON-LD per page from `title` / `summary` / `metadata.meta_tags` /
`metadata.json_ld`: this is what makes each page independently indexable
and citable, not just present in a nav.
- Static output, real HTML: no client-only rendering of the article body.
## 4. Env vars
LETTERSTORY_API_URL=https://app.letterstory.com
LETTERSTORY_API_KEY={{API_KEY}} # server-side / CI secret only
LETTERSTORY_COLLECTION_ID={{COLLECTION_ID}} # optional
Fill in these first
{{API_KEY}}: Dashboard → Settings → API Keys → New Key, tick onlyarticle:read, create it, and copy it immediately: it's shown once. Full walkthrough in KB-401.{{COLLECTION_ID}}: only needed if you're scoping the export to one collection. Ask your agent tolist_collectionsand read the id off the one you want, or drop the query param entirely to pull everything the key can see.
Beyond the first build
GET /api/integrations/published is a convenience route over the same read that every surface shares (list_published / get_published), documented in full, every field, every query param, the OpenAPI schema, at KB-404 and /docs. Reach for those once you're past the first build: paging a large archive, fetching a single article by slug for an on-demand page, or wiring the publish-triggered rebuild this prompt defers.