Skip to content
Docs

The article

An article has one shape. A feed page holds a list of them, a by-slug file holds one, and a webhook sends one, so code that draws one draws them all.

idstring

The article’s ID. It never changes, so use it as your key when you store articles.

slugstring

The last part of the article’s address, to route by. For https://example.com/blog/how-to-brew-green-tea it is how-to-brew-green-tea.

urlstring

The article’s full address on your site. Use it as the canonical address.

titlestring

The title, as plain text.

descriptionstring

The search snippet, for the page’s meta description.

coverobject | null

The cover image as { src, alt }, or null when the article has none.

authorobject | null

The byline as { name, url }, where url is the author’s page or null. The whole field is null when the article is by the site itself.

publishedAtstring

When the article first went live, as an ISO 8601 time in UTC.

modifiedAtstring

When the live version last changed, as an ISO 8601 time in UTC.

htmlstring

The body as HTML, without the title or cover. See The body as HTML.

markdownstring

The same body as Markdown. See The body as Markdown.

structuredDataobject | null

The article’s schema.org JSON-LD, or null when structured data is switched off in the site’s article settings. See Structured data.

The types come with the packages, so there is nothing to copy:

import type { FeedArticle, FeedManifest } from '@citedseo/feed';

This is the file they are defined in, as it is in the package.

@citedseo/feed
/** What every read takes. */
export type FeedOptions = {
/** Your site ID. It is the only thing the feed needs. */
siteId: string
/** Another origin to read from, for tests. Defaults to https://feeds.citedseo.ai. */
origin?: string
/** Your own fetch: a framework's caching one, or a test's. Defaults to the global fetch. */
fetch?: typeof fetch
}
/** An article's schema.org JSON-LD: a BlogPosting, an FAQPage when it has an FAQ, and a BreadcrumbList. */
export type StructuredData = {
"@context": string
"@graph": Record<string, unknown>[]
}
/** One live article, as a feed page holds it, a by-slug file holds it, and a webhook sends it. */
export type FeedArticle = {
/** The article's ID. It never changes, so use it as your key. */
id: string
/** The last part of its address, to route by. */
slug: string
/** The article's full address on your site. Use it as the canonical address. */
url: string
/** The title, as plain text. */
title: string
/** The search snippet, for the page's meta description. */
description: string
/** The cover image, or null when the article has none. */
cover: { src: string; alt: string } | null
/** The byline, or null when the article is by the site itself. */
author: { name: string; url: string | null } | null
/** When the article first went live, as an ISO 8601 time in UTC. */
publishedAt: string
/** When the live version last changed, as an ISO 8601 time in UTC. */
modifiedAt: string
/** The body as HTML, without the title or cover. Safe to insert: no scripts, no raw HTML. */
html: string
/** The same body as Markdown (CommonMark with GitHub's extras). */
markdown: string
/** The article's JSON-LD, or null when the site has structured data switched off. */
structuredData: StructuredData | null
}
/** `feed/index.json`: the one file that changes in place. It names the current build. */
export type FeedManifest = {
/** The current build. It is part of the address of every other file. */
buildId: string
/** How many articles are live. */
total: number
/** How many pages the build has. 0 when nothing is live. */
pageCount: number
/** How many articles a full page holds. */
pageSize: number
/** When the newest article in the build last changed, or null when nothing is live. */
latestModifiedAt: string | null
/** When this build was written. */
generatedAt: string
/** True once the site is gone from CitedSEO: its feed stays empty for good. */
removed?: true
}
/** `b/{buildId}/page-{n}.json`: one page of articles, newest first. */
export type FeedPage = { articles: FeedArticle[] }
/** `b/{buildId}/by-slug/{slug}.json`: one article. */
export type FeedArticleFile = { article: FeedArticle }
/** The events a webhook sends. */
export const webhookEvents = ["article.published", "article.updated"] as const
export type WebhookEvent = (typeof webhookEvents)[number]
/** The JSON body of a webhook. */
export type WebhookPost = {
event: WebhookEvent
/** The same on every try of the same post, so you can tell one you already took. */
delivery: string
/** The article as it is live now. */
data: FeedArticle
}
One article
{
"id": "0b6f6c1e-3f0a-4a59-9d0e-2f8f4c1f7a31",
"slug": "how-to-brew-green-tea",
"url": "https://example.com/blog/how-to-brew-green-tea",
"title": "How to brew green tea",
"description": "Brew green tea at 80°C for two minutes. Here is why the temperature matters and how to get it right without a thermometer.",
"cover": {
"src": "https://example.com/images/green-tea.webp",
"alt": "A glass teapot of green tea"
},
"author": {
"name": "Sam Lee",
"url": "https://example.com/authors/sam-lee"
},
"publishedAt": "2026-10-09T02:05:00.000Z",
"modifiedAt": "2026-10-11T02:05:00.000Z",
"html": "<p class=\"citedseo-answer\"><strong>Brew green tea at 80°C for two minutes. Hotter water makes it bitter.</strong></p>\n<h2 id=\"why-temperature-matters\">Why temperature matters</h2>\n<p>Boiling water pulls out more tannins, which taste <strong>bitter</strong>. See our <a href=\"/blog/tea-guide\">tea guide</a>.</p>\n<aside class=\"citedseo-callout citedseo-tip\"><p><strong>Tip</strong></p><p>No thermometer? Let boiled water stand for three minutes.</p></aside>\n<ol>\n<li>Heat the water to 80°C.</li>\n<li>Steep for two minutes.</li>\n<li>Pour and serve.</li>\n</ol>\n<table>\n<thead>\n<tr>\n<th>Tea</th>\n<th>Temperature</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Green</td>\n<td>80°C</td>\n</tr>\n<tr>\n<td>Black</td>\n<td>95°C</td>\n</tr>\n</tbody>\n</table>\n<h2 id=\"faq\">Frequently asked questions</h2>\n<h3>Can I use boiling water?</h3>\n<p>You can, but the tea will taste bitter.</p>\n<h2 id=\"sources\">Sources</h2>\n<ol class=\"citedseo-sources\">\n<li><a href=\"https://example.org/brewing\">Brewing temperatures</a>, Example Tea Board</li>\n</ol>",
"markdown": "**Brew green tea at 80°C for two minutes. Hotter water makes it bitter.**\n\n## Why temperature matters\n\nBoiling water pulls out more tannins, which taste **bitter**. See our [tea guide](/blog/tea-guide).\n\n> [!TIP]\n> No thermometer? Let boiled water stand for three minutes.\n\n1. Heat the water to 80°C.\n2. Steep for two minutes.\n3. Pour and serve.\n\n| Tea | Temperature |\n| - | - |\n| Green | 80°C |\n| Black | 95°C |\n\n## Frequently asked questions\n\n### Can I use boiling water?\n\nYou can, but the tea will taste bitter.\n\n## Sources\n\n1. [Brewing temperatures](https://example.org/brewing), Example Tea Board",
"structuredData": {
"@context": "https://schema.org",
"@graph": [
{
"@type": "BlogPosting",
"@id": "https://example.com/blog/how-to-brew-green-tea#article",
"headline": "How to brew green tea",
"description": "Brew green tea at 80°C for two minutes. Here is why the temperature matters and how to get it right without a thermometer.",
"url": "https://example.com/blog/how-to-brew-green-tea",
"mainEntityOfPage": "https://example.com/blog/how-to-brew-green-tea",
"inLanguage": "en",
"datePublished": "2026-10-09T02:05:00.000Z",
"dateModified": "2026-10-11T02:05:00.000Z",
"wordCount": 69,
"author": {
"@type": "Person",
"name": "Sam Lee",
"url": "https://example.com/authors/sam-lee"
},
"publisher": {
"@type": "Organization",
"name": "Example Tea",
"url": "https://example.com"
},
"image": "https://example.com/images/green-tea.webp",
"citation": [
"https://example.org/brewing"
]
},
{
"@type": "FAQPage",
"@id": "https://example.com/blog/how-to-brew-green-tea#faq",
"mainEntity": [
{
"@type": "Question",
"name": "Can I use boiling water?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can, but the tea will taste bitter."
}
}
]
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Example Tea",
"item": "https://example.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Blog",
"item": "https://example.com/blog"
},
{
"@type": "ListItem",
"position": 3,
"name": "How to brew green tea",
"item": "https://example.com/blog/how-to-brew-green-tea"
}
]
}
]
}
}