Skip to main content

Overview

This guide uses:
  • Astro 5.x
  • Server-side fetch in frontmatter
  • Static blog index and dynamic post pages via getStaticPaths

1. Configure environment variables

# .env
SKAYLE_API_BASE_URL=https://api.skayle.ai
SKAYLE_ORG_ID=your_organization_id

2. Add a CMS client helper

Create src/lib/skayle-cms.ts:
const API_BASE = import.meta.env.SKAYLE_API_BASE_URL || "https://api.skayle.ai";
const ORG_ID = import.meta.env.SKAYLE_ORG_ID;

if (!ORG_ID) throw new Error("Missing SKAYLE_ORG_ID");

export type JsonApiResource<T = Record<string, unknown>> = {
	id: string;
	type: string;
	attributes: T;
};

export async function fetchSkayle<T>(path: string): Promise<T> {
	const res = await fetch(`${API_BASE}/v1/${ORG_ID}${path}`);
	if (!res.ok) throw new Error(`Skayle request failed: ${res.status}`);
	return res.json() as Promise<T>;
}

3. Build blog listing page

Create src/pages/blog/index.astro:
---
import { fetchSkayle, type JsonApiResource } from "../../lib/skayle-cms";

type CmsPost = { title: string; slug: string; excerpt: string | null };

type ListResponse = { data: Array<JsonApiResource<CmsPost>> };

const response = await fetchSkayle<ListResponse>(
	"/articles?status=published&orderby=date&order=desc&page=1&per_page=50",
);
const posts = response.data;
---

<html>
	<body>
		<h1>Blog</h1>
		<ul>
			{posts.map((post) => (
				<li>
					<a href={`/blog/${post.attributes.slug}`}>{post.attributes.title}</a>
				</li>
			))}
		</ul>
	</body>
</html>

4. Build dynamic blog detail page

Create src/pages/blog/[slug].astro:
---
import { fetchSkayle, type JsonApiResource } from "../../lib/skayle-cms";

type CmsPost = {
	title: string;
	slug: string;
	excerpt: string | null;
	content_html: string | null;
};

type ListResponse = { data: Array<JsonApiResource<CmsPost>> };
type SingleResponse = { data: JsonApiResource<CmsPost> | null };

export async function getStaticPaths() {
	const list = await fetchSkayle<ListResponse>(
		"/articles?status=published&orderby=date&order=desc&page=1&per_page=100",
	);

	return list.data.map((post) => ({
		params: { slug: post.attributes.slug },
	}));
}

const { slug } = Astro.params;
const postResponse = await fetchSkayle<SingleResponse>(`/articles/${encodeURIComponent(slug || "")}`);
const post = postResponse.data;

if (!post) {
	throw new Error("Post not found");
}
---

<html>
	<body>
		<article>
			<h1>{post.attributes.title}</h1>
			{post.attributes.excerpt ? <p>{post.attributes.excerpt}</p> : null}
			<div set:html={post.attributes.content_html || ""} />
		</article>
	</body>
</html>

5. Static build flow

Run a static build with:
npm run build
Astro generates listing and post pages from Skayle CMS data at build time. For frequent content updates, schedule regular builds or use Astro hosting features that support on-demand rendering.

6. Use non-article collections (optional)

If you enabled additional collections/content types in Skayle CMS, fetch them via collection-scoped items. Non-article collections are available on the Authority plan.
const answers = await fetchSkayle<ListResponse>(
	"/collections/answers/items?status=published&page=1&per_page=50",
);
/posts still works as a backward-compatible alias, but new code should use /articles.