Data Loading
The PerspectAPI v2 SDK provides direct methods for loading content, products, and categories with cursor-based pagination and auto-pagination support.
Quick Start
import { PerspectApiV2Client } from 'perspectapi-ts-sdk';
const client = new PerspectApiV2Client({
baseUrl: process.env.PERSPECTAPI_BASE_URL!,
apiKey: process.env.PERSPECTAPI_API_KEY!
});
// Load published posts
const posts = await client.content.list('my-site', {
type: 'post',
status: 'publish',
limit: 10
});
// Load products
const products = await client.products.list('my-site', {
published: true,
limit: 20
});
Content
List Content
const posts = await client.content.list('my-site', {
type: 'post', // "post" | "page" | "block"
status: 'publish', // "draft" | "publish" | "private" | "trash" | "scheduled"
limit: 10,
slug_prefix: 'blog',
search: 'tutorial'
});
// Response:
// {
// object: "list",
// data: [{ object: "content", id: "cnt_42", title: "...", ... }],
// has_more: true,
// url: "/v2/sites/my-site/content"
// }
Get by ID or Slug
// By prefixed ID
const post = await client.content.get('my-site', 'cnt_42');
// By slug
const post = await client.content.get('my-site', 'getting-started');
Auto-Paginate All Content
for await (const post of client.content.listAutoPaginated('my-site', {
type: 'post',
status: 'publish'
})) {
console.log(post.title);
}
Products
List Products
const products = await client.products.list('my-site', {
published: true,
category_id: 'cat_5',
slug_prefix: 'widgets',
limit: 20
});
Get by ID or Slug
const product = await client.products.get('my-site', 'prod_123');
const product = await client.products.get('my-site', 'premium-widget');
Auto-Paginate
for await (const product of client.products.listAutoPaginated('my-site', {
published: true
})) {
console.log(`${product.name}: $${product.price}`);
}
Categories
const categories = await client.categories.list('my-site', {
type: 'product' // "post" | "product"
});
Server Framework Examples
Remix Loader
import { PerspectApiV2Client } from 'perspectapi-ts-sdk';
export async function loader() {
const client = new PerspectApiV2Client({
baseUrl: process.env.API_URL!,
apiKey: process.env.API_KEY!
});
const [posts, products] = await Promise.all([
client.content.list('my-site', { type: 'post', status: 'publish', limit: 10 }),
client.products.list('my-site', { published: true, limit: 12 }),
]);
return { posts: posts.data, products: products.data };
}
Next.js App Route
import { PerspectApiV2Client } from 'perspectapi-ts-sdk';
const client = new PerspectApiV2Client({
baseUrl: process.env.API_URL!,
apiKey: process.env.API_KEY!
});
export default async function BlogPage() {
const posts = await client.content.list('my-site', {
type: 'post',
status: 'publish',
limit: 20
});
return (
<div>
{posts.data.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.slug}</p>
</article>
))}
{posts.has_more && <LoadMoreButton />}
</div>
);
}
Cloudflare Worker
import { PerspectApiV2Client } from 'perspectapi-ts-sdk';
export default {
async fetch(request: Request, env: Env) {
const client = new PerspectApiV2Client({
baseUrl: env.API_URL,
apiKey: env.API_KEY
});
const url = new URL(request.url);
const slug = url.pathname.slice(1); // e.g., "/my-post" -> "my-post"
const post = await client.content.get('my-site', slug);
return new Response(JSON.stringify(post), {
headers: { 'Content-Type': 'application/json' }
});
}
};
Cursor Pagination
All list methods use cursor-based pagination via starting_after and ending_before:
// First page
const page1 = await client.content.list('my-site', { limit: 10 });
// Next page (using the last item's ID as cursor)
if (page1.has_more) {
const lastId = page1.data[page1.data.length - 1].id;
const page2 = await client.content.list('my-site', {
limit: 10,
starting_after: lastId
});
}
Or use listAutoPaginated() to iterate all items automatically:
const allPosts: V2Content[] = [];
for await (const post of client.content.listAutoPaginated('my-site', { type: 'post' })) {
allPosts.push(post);
}