@kookee/sdk is a zero-dependency TypeScript client built on native fetch. Type definitions are included — there is no separate @types package.
Install
npm install @kookee/sdk
# or: pnpm add @kookee/sdk / yarn add @kookee/sdk / bun add @kookee/sdk
Create a client
import { Kookee } from '@kookee/sdk';
const kookee = new Kookee({
apiKey: process.env.KOOKEE_API_KEY!,
});
Constructor options:
apiKey(string) — your project API key. An error is thrown if neitherapiKeynorprojectIdis given.projectId(string, optional) — can take the place ofapiKey, but only while the project's hosted portal is enabled; otherwise the API answers 403PORTAL_NOT_ENABLED.baseUrl(string, optional) — override the API base URL.timeoutMs(number, optional) — abort any request that takes longer than this. Node'sfetchhas no deadline of its own; chat streams are exempt.
Create the client once and export it, rather than constructing a new one per request.
Available modules
kookee.blog— posts, tags, reactionskookee.changelog— entries, reactionskookee.help— articles, categories, searchkookee.pages— static pageskookee.config— key-value configurationkookee.announcements— in-app announcementskookee.feedback— feedback posts, board columns and comments (read-only; visitors post and vote on your hosted portal)kookee.entries— any of the types above, by its slugkookee.widget— the site widget's settings, andsendFeedback(), which sends a private feedback message for your team to review on the dashboard's Feedback pagekookee.project— the project's name, default language, hosted portal address and whether its widget settings are savedkookee.status— the status page, with its components, incidents and maintenance, and one incident with its updates
React and Next.js
Put the client in one module and import it everywhere:
// lib/kookee.ts
import { Kookee } from '@kookee/sdk';
export const kookee = new Kookee({ apiKey: process.env.KOOKEE_API_KEY! });
// app/blog/page.tsx
import { kookee } from '@/lib/kookee';
export default async function BlogPage() {
const response = await kookee.blog.list();
return (
<ul>
{response.data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Fetching in a server component means one API call serves every visitor to the page, which is the right default for content that rarely changes.
Node.js and Express
import express from 'express';
import { Kookee } from '@kookee/sdk';
const app = express();
const kookee = new Kookee({ apiKey: process.env.KOOKEE_API_KEY! });
app.get('/api/posts', async (req, res) => {
const response = await kookee.blog.list();
res.json(response);
});
Vite and Vue
Vite exposes only variables prefixed with VITE_ to client code:
const kookee = new Kookee({ apiKey: import.meta.env.VITE_KOOKEE_API_KEY });
Anything exposed this way is visible in your bundle. That is fine: the API key reads published content and cannot edit or publish anything — see API keys and security. List your site's domains under Allowed Origins in Settings → Project, so other sites cannot use the key from a browser.
TypeScript
Response types are exported for annotating your own functions:
import {
Kookee,
type BlogEntryListItem,
type HelpArticleListItem,
type HelpArticleDetail,
} from '@kookee/sdk';
function renderPosts(posts: BlogEntryListItem[]) {
// ...
}
function renderArticleIndex(articles: HelpArticleListItem[]) {
// ...
}
function renderArticle(article: HelpArticleDetail) {
// ...
}
The names follow one convention: list responses are ...ListItem and detail responses are ...Detail. So help.list() gives you HelpArticleListItem and help.getBySlug() gives you HelpArticleDetail, with the same pairing across blog, pages, changelog and announcements.
Using React?
@kookee/react adds hooks and ready-made components on top of this client: see Reading Kookee content with React hooks and React components for your blog, changelog and help center.
No build step?
If you are working on a static site or a CMS-hosted page, use the CDN build instead — see Using Kookee from a script tag.