Blog namespace

Reference for blog posts, tags, authors, adjacent posts, related posts, and search.

Use board.blog to render published posts, tag and author archives, adjacent navigation, related content, and search. These reads are public; your frontend owns routes, layout, metadata, and safe rendering of the returned HTML. Check board.context().features.blog before exposing blog navigation.

Shared behavior

Every method returns the Board API wire body unchanged and throws BoardApiError for a non-2xx response. The final FetchOptions argument passes abort signals, headers, and framework cache directives through to fetch.

List and search envelopes include object, url, hasMore, nextCursor, and data. Post lists return PublicBlogPostSummary; only a post detail includes its html body and SEO fields.

board.blog.posts.list

List published posts, newest first.

ts
board.blog.posts.list(
query?: BlogPostsListQuery,
options?: FetchOptions,
): Promise<ListEnvelope<PublicBlogPostSummary>>
FieldTypeBehavior
cursorstringOpaque cursor from nextCursor.
limitnumberPage size from 1 to 100.
tagSlugstringRestrict posts to one tag.
authorSlugstringRestrict posts to one author.
featured'true'Restrict the list to featured posts.
ts
const page = await board.blog.posts.list({
tagSlug: 'product-news',
featured: 'true',
limit: 12,
});
for (const post of page.data) {
console.log(post.title, post.slug, post.publishedAt);
}

Summaries contain identity, title/slug, featured state, images, excerpt, reading time, publish/canonical dates, authors, and tags. They do not contain html. A missing/private board returns 404.

Related methods: board.blog.posts.retrieve, board.blog.tags.retrieve, and board.blog.authors.retrieve.

board.blog.posts.retrieve

Retrieve one published post by slug.

ts
board.blog.posts.retrieve(
postSlug: string,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<PublicBlogPost>
ts
const post = await board.blog.posts.retrieve('launching-acme-jobs');
if (post.redirected && post.newSlug) {
console.log('Redirect permanently to:', post.newSlug);
}
console.log(post.title, post.html);

The detail adds html, ogImageUrl, featureImageCaption, seoTitle, seoDescription, redirected, and newSlug to the summary. When a historical slug resolves, emit a permanent redirect to newSlug rather than rendering duplicate content. html can be null; the frontend must own its empty state and rendering policy.

A missing board or post returns blog_post_not_found with status 404.

Related methods: board.blog.posts.adjacent, board.blog.posts.similar, and the SEO guide.

board.blog.posts.adjacent

Retrieve the previous older post and next newer post by publish date.

ts
board.blog.posts.adjacent(
postSlug: string,
options?: FetchOptions,
): Promise<PublicBlogAdjacentPosts>
ts
const adjacent = await board.blog.posts.adjacent('launching-acme-jobs');
console.log('Older:', adjacent.previous?.slug ?? 'none');
console.log('Newer:', adjacent.next?.slug ?? 'none');

Either previous or next can be null at the ends of the archive. A missing board or source post returns blog_post_not_found with status 404.

Related method: board.blog.posts.retrieve.

board.blog.posts.similar

Return published posts related to one post. The source post is excluded.

ts
board.blog.posts.similar(
postSlug: string,
query?: BlogSimilarQuery,
options?: FetchOptions,
): Promise<ListEnvelope<PublicBlogPostSummary>>

query.limit accepts 1–20 and defaults to 6.

ts
const related = await board.blog.posts.similar('launching-acme-jobs', {
limit: 6,
});
for (const post of related.data) {
console.log(post.title);
}

An empty data array is valid. A missing board/post returns 404. Similarity infrastructure failure returns search_unavailable with status 503.

Related method: board.blog.posts.retrieve.

board.blog.tags.list

List all public, non-internal tags.

ts
board.blog.tags.list(
query?: Record<string, never>,
options?: FetchOptions,
): Promise<ListEnvelope<PublicBlogTag>>
ts
const tags = await board.blog.tags.list();
for (const tag of tags.data) {
console.log(tag.name, tag.slug);
}

Each PublicBlogTag contains id, name, slug, description, and the public_blog_tag discriminator. A missing/private board returns 404.

Related methods: board.blog.tags.retrieve and board.blog.posts.list.

board.blog.tags.retrieve

Retrieve one public tag by slug.

ts
board.blog.tags.retrieve(
tagSlug: string,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<PublicBlogTag>
ts
const tag = await board.blog.tags.retrieve('product-news');
const posts = await board.blog.posts.list({ tagSlug: tag.slug });
console.log(tag.name, posts.data.length);

A missing board or tag returns blog_tag_not_found with status 404.

Related method: board.blog.posts.list.

board.blog.authors.list

List active blog authors.

ts
board.blog.authors.list(
query?: Record<string, never>,
options?: FetchOptions,
): Promise<ListEnvelope<PublicBlogAuthor>>
ts
const authors = await board.blog.authors.list();
for (const author of authors.data) {
console.log(author.name, author.slug);
}

Each author contains identity, name/slug, bio, avatar, website, and supported social URLs. A missing/private board returns 404.

Related methods: board.blog.authors.retrieve and board.blog.posts.list.

board.blog.authors.retrieve

Retrieve one active author by slug.

ts
board.blog.authors.retrieve(
authorSlug: string,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<PublicBlogAuthor>
ts
const author = await board.blog.authors.retrieve('jane-doe');
const posts = await board.blog.posts.list({ authorSlug: author.slug });
console.log(author.name, posts.data.length);

A missing board or author returns blog_author_not_found with status 404.

Related method: board.blog.posts.list.

board.blog.search

Search published posts by free text.

ts
board.blog.search(
body: BlogSearchBody,
query?: Record<string, never>,
options?: FetchOptions,
): Promise<SearchEnvelope<PublicBlogPostSummary>>

BlogSearchBody.query is required and accepts up to 200 characters. Optional cursor continues a result set and limit accepts 1–50.

ts
const controller = new AbortController();
const results = await board.blog.search(
{ query: 'launch marketing', limit: 10 },
undefined,
{ signal: controller.signal },
);
for (const post of results.data) {
console.log(post.title, post.slug);
}

This is a POST read. It returns post summaries rather than detail HTML. A missing/private board returns 404; handle validation failures and unavailable search infrastructure through BoardApiError.

Related methods: board.blog.posts.list and board.blog.posts.retrieve.