SEO for SaaS
Start
API reference

TypeScript client

One dependency-free file: list, paginate, read by slug, typed errors. Runs anywhere fetch does.

lib/seoforsaas/client.ts wraps the read endpoints. It needs only fetch (Node 18+, Bun, Deno, Cloudflare Workers) and ships with types.ts, the whole API as TypeScript types. It's a source file in your repository, not a package: read it, and extend it through its options rather than edits, so reinstalling a newer version stays a clean overwrite.

npx shadcn@latest add https://seoforsaas.dev/r/client.json

createClient(options)

ts
import { createClient } from "./lib/seoforsaas/client";const seoforsaas = createClient({  projectId: process.env.SEOFORSAAS_PROJECT_ID,  contentKey: process.env.SEOFORSAAS_CONTENT_KEY,});
OptionType
projectIdstring | undefinedDelivery → Connection. Required.
contentKeystring | undefinedRequired.
apiUrlstringDefaults to https://api.seoforsaas.dev.
requestInitRequestInit without headers, method, body and signalMerged into every request: framework cache options go here, for example { cache: "force-cache", next: { tags: ["seoforsaas"] } } in Next.js.
timeoutMsnumberPer request. Defaults to 10000.

projectId and contentKey accept undefined so you can pass environment variables as they are: a missing one throws at once, naming the variable.

Methods

MethodReturns
listArticles({ page?, limit? }){ articles: Article[], pagination }One page, newest first. limit defaults to 100 here (the API's own default is 20) and is capped at 100.
listAllArticles()Article[]Every page. For indexes and static params.
getArticle(slug)ArticleDetail | nullWith related (always an array); null when there's no published article at that slug.
getSitemap()SitemapEntry[]{ url, lastModified } per published article, newest change first. See Sitemap.

The methods are plain functions: destructuring them (const { getArticle } = seoforsaas) works.

Errors

A non-2xx response other than a missing article throws SeoForSaasError with the HTTP status and the API's error code. A timeout throws the platform's TimeoutError, and a network failure its TypeError, unchanged:

ts
import { createClient, SeoForSaasError } from "./lib/seoforsaas/client";const seoforsaas = createClient({  projectId: process.env.SEOFORSAAS_PROJECT_ID,  contentKey: process.env.SEOFORSAAS_CONTENT_KEY,});export async function loadArticles() {  try {    return await seoforsaas.listAllArticles();  } catch (error) {    if (error instanceof SeoForSaasError && error.status === 401) {      throw new Error("SEOFORSAAS_CONTENT_KEY is wrong or was revoked", { cause: error });    }    throw error;  }}

Codes are listed under Errors and limits.