Skip to contentDevelopersPrezly website
Build a newsroom

JavaScript SDK

Use the typed Prezly client to read stories, select content formats, and handle API failures.

@prezly/sdk wraps the Prezly API with typed resource methods. It handles request construction and common response envelopes; it does not render story content or grant additional API permissions.

These examples use Node.js 22 or later, which provides fetch. Run authenticated calls in server code or a local script, with a personal token or integration key. Keep the token out of browser bundles and public environment variables.

Install the client

pnpm add @prezly/sdk

Load PREZLY_API_TOKEN as shown in Your first API request. A personal token needs stories:read for the story calls below; add sites:read if you also list newsrooms.

Read a story in format v6

Replace YOUR_STORY_UUID, save as read-story.mjs, and run node read-story.mjs:

import { ApiError, createPrezlyClient, Story } from '@prezly/sdk';

const token = process.env.PREZLY_API_TOKEN;
if (!token) throw new Error('Set PREZLY_API_TOKEN before running this script.');
const client = createPrezlyClient({ accessToken: token });

try {
  const story = await client.stories.get('YOUR_STORY_UUID', {
    formats: [Story.FormatVersion.SLATEJS_V6],
  });
  const document = JSON.parse(story.content);
  console.log(story.uuid, story.title, document.version);
} catch (error) {
  if (error instanceof ApiError) {
    console.error(`Prezly returned HTTP ${error.status}.`);
  }
  throw error;
}

Unlike the raw HTTP response { story: ... }, client.stories.get() returns the story object directly. Its content field remains a JSON-encoded string; the SDK does not turn it into a parsed content document. formats requests the API's conversion through the Accept header; it does not convert or save content in your application.

See Story rendering to pass the parsed document to the React renderer. The SDK and renderer are separate packages with different jobs.

Filter and page through story results

With the same client and imports, use stories.search() for structured conditions. Replace YOUR_NEWSROOM_UUID:

const { stories, pagination } = await client.stories.search({
  query: {
    'newsroom.uuid': { $in: ['YOUR_NEWSROOM_UUID'] },
    status: { $in: ['published'] },
    visibility: { $in: ['public'] },
  },
  limit: 50,
  offset: 0,
  sortOrder: '-published_at',
  include: ['content'],
  formats: [Story.FormatVersion.SLATEJS_V6],
});
console.log(stories.length, pagination.matched_records_number);

stories.search() uses the read-only POST /stories/search endpoint. It does not create or update stories. Its response keeps the stories array and pagination object. Request subsequent pages by increasing offset using the returned pagination values, as explained in Pagination and sorting.

The client methods are not interchangeable:

TaskSDK methodImportant detail
List available newsroomsclient.newsrooms.list({ limit: 5, offset: 0 })Returns newsrooms and pagination; a personal token needs sites:read.
List stories without structured filtersclient.stories.list({ limit: 50, offset: 0 })Accepts free-form search, but not a structured query option.
Filter storiesclient.stories.search({ query, ...options })Pass a query object; the client handles serialization.
Read one full storyclient.stories.get(uuid, { formats })Returns the story directly. Prefer UUIDs for new code.

SDK options use sortOrder, while the HTTP API uses sort. The include array controls optional response fields such as list-item content. The formats array selects content formats; it does not make omitted fields appear. See Filtering results for valid query operators and Search Stories for the endpoint-specific contract.

Handle errors and endpoint permissions

An HTTP rejection is an ApiError with status, payload, and response headers. A network failure can be a different error. Inspect the status and optional payload fields instead of assuming every exception is an authentication error. See Handling errors for retry decisions and the personal-token error codes.

The SDK exposes more operations than any one credential may use. Token scopes, endpoint support, and resource access still apply. For example, personal tokens cannot poll the Jobs API; a method that waits for a background job may require a different approach. The SDK's presence of a method is not proof your token can call every request it makes.

The client's default API origin is https://api.prezly.com. If you supply baseUrl for a test server, use its origin, without appending /v2; the resource methods already include their API paths. You can also supply a custom fetch implementation to apply your application's timeout or instrumentation policy.

The examples were checked with SDK 26.16.0, renderer 0.45.1, and story-content-format 0.72.0. Keep package upgrades deliberate and verify the blocks your authors use. The Bea starter shows how the SDK, renderer, routing, and newsroom styling fit together in a complete application.

For write workflows, start with Creating and updating stories, Importing HTML, and Story translations. Check each endpoint’s credential support before replacing a raw request with an SDK method.

On this page