Search documentation

Search documentation

Getting Started

Configure the SDK

Configure the shared Contoprix client, authentication, and environment variables.

Configure one client, then reuse it#

Create the Contoprix client once in a server-side module. This gives every request the same base URL, authentication method, timeout, and default language.

One-client pattern
environment variables → ContoprixClient → data mapper → page/component

Do not create a new client inside every presentational component, and do not put a management secret in browser code.

1. Add environment variables#

For a frontend that reads published content, use a delivery key:

.env.local
CONTOPRIX_BASE_URL=https://cms.example.com
CONTOPRIX_DELIVERY_KEY=replace-with-your-delivery-key

CONTOPRIX_BASE_URL is the CMS API origin. The client adds paths such as /api/delivery/content/... itself, so do not append /api.

Important

Never use NEXT_PUBLIC_CONTOPRIX_DELIVERY_KEY, NEXT_PUBLIC_CONTOPRIX_CLIENT_SECRET, or a similar public variable for a credential. In Next.js, NEXT_PUBLIC_ values are bundled into browser JavaScript.

2. Create the shared client#

src/lib/contoprix/client.ts
import "server-only";

import { ContoprixClient } from "@contoprix/client";

const baseUrl = process.env.CONTOPRIX_BASE_URL;
const deliveryKey = process.env.CONTOPRIX_DELIVERY_KEY;

if (!baseUrl || !deliveryKey) {
  throw new Error("CONTOPRIX_BASE_URL and CONTOPRIX_DELIVERY_KEY are required.");
}

export const client = new ContoprixClient({
  baseUrl,
  auth: {
    type: "deliveryKey",
    deliveryKey,
  },
  languageCode: "en",
  timeout: 30_000,
});

The languageCode is the default for calls that do not specify a language. A per-request language always overrides it.

Choose the right authentication method#

Auth typeGood forWhat the SDK sendsWhere it belongs
deliveryKeyPublished delivery for one websitex-contoprix-delivery-keyServer-side delivery code; use a tightly scoped key
clientCredentialsTrusted server-to-server SDK operationsThe SDK exchanges ID and secret for a bearer tokenServer-side only
accessTokenAn already authenticated protected workflowAuthorization: Bearer ...Server-side or a protected backend boundary

Delivery key: normal public-site delivery#

Delivery key configuration
auth: {
  type: "deliveryKey",
  deliveryKey: process.env.CONTOPRIX_DELIVERY_KEY!,
}

This is the usual choice for a website that reads published pages and entries. The key determines the website context, so the SDK does not ask you to send a website ID on each request.

Client credentials: trusted service integration#

Client credentials configuration
auth: {
  type: "clientCredentials",
  clientId: process.env.CONTOPRIX_CLIENT_ID!,
  clientSecret: process.env.CONTOPRIX_CLIENT_SECRET!,
}

The SDK obtains and caches a bearer token from the CMS token endpoint, refreshing it before it expires. Keep both values on a server. Client credentials are also what the CLI uses for schema operations, subject to its granted scopes.

Access token: use an existing bearer token#

Access token configuration
auth: {
  type: "accessToken",
  accessToken: existingAccessToken,
}

Use this only when your backend already has a valid token. The environment helper does not infer an access-token configuration for you; construct this form explicitly.

Fetch a page#

Use pages.get() for the root page and pages.getBySlug() for a named path:

src/lib/contoprix/pages.ts
import { client } from "./client";

export const getHomePage = () => client.pages.get({ languageCode: "en" });

export const getAboutPage = () =>
  client.pages.getBySlug("/about", { languageCode: "en" });

A delivered page has page metadata such as name, slug, languageCode, and an ordered blocks array. Its block data is rendered through a component registry; see Visual Builder Setup when you are ready to render CMS-composed pages.

Fetch one content entry by slug#

src/lib/contoprix/articles.ts
import { client } from "./client";

type ArticleData = {
  title?: string;
  summary?: string;
};

export async function getArticle(slug: string, languageCode = "en") {
  const entry = await client.content.getBySlug("article", slug, {
    languageCode,
  });

  const data = entry.data as ArticleData;

  return {
    id: entry.id,
    slug: entry.slug,
    languageCode: entry.languageCode,
    title: data.title ?? "Untitled article",
    summary: data.summary ?? "",
  };
}

The method signature is:

Content lookup signature
client.content.getBySlug(contentTypeCode, slug, { languageCode? })

It requests one published entry. The content-type code and slug are normalized for delivery; use the values that exist in the CMS model and entry.

Fetch a list safely#

List the newest Articles
const result = await client.content.list({
  contentType: "article",
  languageCode: "en",
  take: 12,
  skip: 0,
  sort: "newest",
});

const articles = result.items;
const { total, hasNext } = result.pagination;

The delivery list supports a content-type code, language, take, skip, and newest or oldest sorting. take is limited to 100 by the delivery API. Although the SDK type has a filters property for future-compatible clients, the current REST delivery list does not apply arbitrary field filters; do not build a production feature that depends on them yet.

Override the language for a request#

Do not mutate the shared client just because one route needs another locale. Pass the locale on the call instead:

Request French content
const frenchArticle = await client.content.getBySlug("article", "hello-contoprix", {
  languageCode: "fr",
});

The requested language must exist for the delivery-key website, and the matching entry must be published. Read Localization before adding locale routes.

Next.js server helpers#

@contoprix/next/server can create a client from the same server environment variables:

src/app/[...slug]/page.tsx
import { getContoprixPage } from "@contoprix/next/server";

const page = await getContoprixPage({
  slug: "/about",
  languageCode: "en",
});

getContoprixContent() is also available when you already know the entry ID. For a lookup by slug, call createContoprixClient().content.getBySlug(...) or use your own shared client as shown above.

Keep SDK code server-side#

Use the client in a Server Component, route handler, server action, or backend service. Pass only the mapped data needed by an interactive Client Component.

Good boundary
Server: SDK request + credential + mapping
Browser: rendered props + user interaction

This protects credentials, makes failed delivery calls easier to handle consistently, and prevents each UI component from needing to understand the full CMS response.

Configuration checklist#

  • CONTOPRIX_BASE_URL is the API origin, without /api.
  • The delivery key belongs to the website that owns the pages and entries.
  • The default languageCode is a configured website language.
  • All custom content fields are read from entry.data.
  • A request-specific locale is passed on the SDK call, not stored in a mutable global.
  • Delivery and preview credentials are kept in server-side code.

Next, use Content Types to design the data you will read, or Create your first project for the complete Article walkthrough.